# %%
PROJECT_PATH = '/home/md/Work/ligalytics/leagues_stable/'
import os, sys
sys.path.insert(0, PROJECT_PATH)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "leagues.settings")
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"

from leagues import settings
settings.DATABASES['default']['NAME'] = PROJECT_PATH+'/db.sqlite3'
# settings.DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
# settings.DATABASES['default']['HOST'] = '0.0.0.0'
# settings.DATABASES['default']['PORT'] = '5432'
# settings.DATABASES['default']['USER'] = 'postgres'
# settings.DATABASES['default']['PASSWORD'] = 'secret123'
# settings.DATABASES['default']['NAME'] = 'mypgsqldb'
# settings.DATABASES['default']['ATOMIC_REQUESTS'] = False
# settings.DATABASES['default']['AUTOCOMMIT'] = True
# settings.DATABASES['default']['CONN_MAX_AGE'] = 0
# settings.DATABASES['default']['CONN_HEALTH_CHECKS'] = False
# settings.DATABASES['default']['OPTIONS'] = {}

os.environ["XPRESSDIR"] = "/opt/xpressmp"
os.environ["XPRESS"] = "/opt/xpressmp/bin"
os.environ["LD_LIBRARY_PATH"] = os.environ["XPRESSDIR"] + "/lib"
os.environ["DYLD_LIBRARY_PATH"] = os.environ["XPRESSDIR"] + "/lib"
os.environ["SHLIB_PATH"] = os.environ["XPRESSDIR"] + "/lib"
os.environ["LIBPATH"] = os.environ["XPRESSDIR"] + "/lib"
os.environ["PYTHONPATH"] = os.environ["XPRESSDIR"] + "/lib"
os.environ["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprs.jar"
os.environ["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprb.jar" + os.pathsep + os.environ["CLASSPATH"]
os.environ["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprm.jar" + os.pathsep + os.environ["CLASSPATH"]
os.environ["PATH"] = os.environ["XPRESSDIR"] + "/bin" + os.pathsep + os.environ["PATH"]


import django
django.setup()

from scheduler.models import *
import pulp
from pulp import lpSum, value, XPRESS, GUROBI, PULP_CBC_CMD, XPRESS_PY
import xpress as xp
from django.db.models import Q
from django.template.loader import render_to_string

from qualifiers.models import *
from common.models import GlobalTeam, GlobalCountry
from common.functions import getRandomHexColor
from scheduler.models import Season, Scenario, Team, DayObj, CountryClash, Country

from qualifiers.draws import groupTeams, optimize_inversions4
from scheduler.solver.tasks.optimize import optimize

import random
import time
import json
import csv
import networkx as nx
import matplotlib.pyplot as plt
from datetime import timedelta

# %%






# import requests

# data = json.loads(b'{\r\n    "season": "UCL 24/25",\r\n    "team": 52277,\r\n    "pots": [1,2,3,4],\r\n    "games":[[50051, 52747], [50138, 50051], [50051, 50147]]\r\n}')
# headers = {'Content-type': 'application/json', 'Authorization': 'R6v1e9Q5W8aS3b7C4x2KpZqL9yFmXnDz'}

# requests.post('http://localhost:8000/draws/checker/',json=data, headers=headers)




# %%
# # scenario.sol_solution
scenario = Scenario.objects.get(id=1)

"""GUROBI"""


scenario_id = scenario.id
fixed_games = []
print("\n")
ttt = time.time()
tt = time.time()
scenario = Scenario.objects.get(id=scenario_id)
teamObjects = Team.objects.filter(season=scenario.season,active=True).exclude(name='-').values()
teams = [t['id'] for t in teamObjects]
t_pot = {t['id'] : t['pot'] for t in teamObjects}
t_name = {t['id'] : t['name'] for t in teamObjects}
t_country = {t['id'] : t['countryObj_id'] for t in teamObjects if  t['countryObj_id'] }
t_master = {t['id'] : None for t in teamObjects}
pots = sorted(list(set(t_pot.values())))
p_teams = { p:[t for t in teams if t_pot[t]==p] for p in pots }
countries = [c.id for c in scenario.season.countries.all()] 
teams_from_country = { c:[t for t in teams if t_country[t]==c] for c in countries }
# print ("CHECKING", len(fixed_games) , "games!")

drawFound = False
for draw in Draw.objects.filter(season=scenario.season, active=True ):
    drawFound = True
    # print ("DRAW  ",draw)

supergroups = []
sg_teams = {}
sg_groups = {}
sg_pots = {}
sg_games_per_team = {}
sg_games_against_pot = {}
for sg in SuperGroup.objects.filter(draw = draw):
    supergroups.append(sg.id)
    # sg_teams[sg.id]  = [ t.id for t in sg.teams.all()]
    # sg_groups[sg.id] = [ t.id for t in sg.groups.all()]
    sg_teams[sg.id]  = sg.teams.values_list('id',flat=True)
    sg_groups[sg.id]  = sg.groups.values_list('id',flat=True)

    maxpot = max([ t_pot[t] for t in sg_teams[sg.id]])
    sg_pots[sg.id]=range(1, maxpot+1)
    sg_games_per_team[sg.id]= sg.gamesPerTeam
    sg_games_against_pot[sg.id]= sg_games_per_team[sg.id]/maxpot
    for t in sg_teams[sg.id]:
        t_master[t]=sg.id


    possible_opponents = { (t,p): [t2 for t2 in sg_teams[sg.id] if t_country[t2]!=t_country[t] and t_pot[t2]==p] for t in sg_teams[sg.id] for p in pots}



print("\t1",time.time()-tt)
tt = time.time()

model = xp.problem(name='Draws', sense=xp.minimize)
model.setControl ('outputlog', 0)

x = {}

gameVarExists= { (t1,t2): False for t1 in teams for t2 in teams}

for sg in supergroups:
    for t1 in sg_teams[sg]:
        for t2 in sg_teams[sg]:
            if t_country[t1] != t_country[t2]:
                # x[t1, t2] = pulp.LpVariable('x_'+str(t1)+'_'+str(t2),lowBound=0, upBound=1, cat=pulp.LpInteger)
                x[t1, t2] = xp.var(ub=1, vartype=xp.integer)
                gameVarExists[(t1,t2)]=True
    model.addVariable(x)
    # REQUIREMENTS
    for t in sg_teams[sg]:
        for p in sg_pots[sg]:
            if sg_games_against_pot[sg]==2:
                model.addConstraint(xp.Sum(x[t,t2] for t2 in p_teams[p] if gameVarExists[(t,t2)]) == 1)
                model.addConstraint(xp.Sum(x[t2,t] for t2 in p_teams[p] if gameVarExists[(t2,t)]) == 1)
            else:
                model.addConstraint(xp.Sum(x[t,t2] for t2 in p_teams[p] if gameVarExists[(t,t2)]) <= 1)
                model.addConstraint(xp.Sum(x[t2,t] for t2 in p_teams[p] if gameVarExists[(t2,t)]) <= 1)
                model.addConstraint(xp.Sum(x[t2,t] + x[t,t2] for t2 in p_teams[p] if gameVarExists[(t,t2)]) == sg_games_against_pot[sg])
                if p%2==0:
                    # exactly one home game against pots 1,2, one against pot 3,4 one against pots 5,6
                    model.addConstraint(xp.Sum(x[t,t2] for t2 in p_teams[p-1]+p_teams[p] if gameVarExists[(t,t2)]) == 1)
    
        for c in countries:
            if c != t_country[t]:
                tcnt = [t2 for t2 in teams_from_country[c] if t_master[t]==t_master[t2]] 
                if len(tcnt)>draw.max_opponents_from_same_country:
                    model.addConstraint(xp.Sum(x[t,t2]+x[t2,t] for t2 in teams_from_country[c] if t_master[t]==t_master[t2] and gameVarExists[(t,t2)]) <= draw.max_opponents_from_same_country)


print("\t2",time.time()-tt)
tt = time.time()

for cl in draw.clashes.filter(type="Game").prefetch_related('countries','teams'):
    # cl_countries =  [ c.id for c in cl.countries.all() ]
    cl_countries =  cl.countries.values_list('id',flat=True)
    cl_teams = list(cl.teams.values_list('id',flat=True)) + [ t for t in teams if t_country[t] in cl_countries ]
    cl_teams = list(set(cl_teams))
    # print("CLASH" ,cl, cl_countries , cl_teams , [ (t_name[t] , t_country[t]) for t in cl_teams ]  )
    if cl.minTeams>0:
        model.addConstraint(xp.Sum(x[t1,t2] for t1 in cl_teams for t2 in cl_teams if gameVarExists[(t1,t2)]) >= cl.minTeams)
        # print ("min implemented")
    if len(cl_teams)>1:
        model.addConstraint(xp.Sum(x[t1,t2] for t1 in cl_teams for t2 in cl_teams if gameVarExists[(t1,t2)]) <= cl.maxTeams)
        # print ("max implemented")

print("\t3",time.time()-tt)
# FIXATIONS
for (t1,t2) in fixed_games:
    if gameVarExists[(t1,t2)]:
        model += x[t1,t2] == 1
    else:
        print ("GAME DOES NOT EXIST!!")
        print( False)

print("\t3",time.time()-tt)
# for (t1,t2) in [(t1,t2) for (t1,t2) in x.keys() if t1 < t2]:
for (t1,t2) in [(t1,t2) for (t1,t2) in x.keys() if t1 < t2]:
    model.addConstraint(x[t1,t2] + x[t2,t1] <= 1)
    # model.addConstraint(x[t1,t2] + x[t2,t1] <= 1)

print("\t4",time.time()-tt)
# model.solve(XPRESS(msg=0,timeLimit=120,keepFiles=0))
tt = time.time()

# model.solve(XPRESS_PY(msg=0,timeLimit=120))
model.solve()
# model.solve(GUROBI(msg=0,timeLimit=120))

# model.solve(PULP_CBC_CMD(timeLimit = 120, threads = 8,msg=0))

print("\t5",time.time()-tt)
print("TIME",time.time()-ttt)