# %%
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"
import random

# XPRESS ENVIRONMENT
os.environ['XPRESSDIR'] = "/opt/xpressmp_8.4"
os.environ['XPRESS'] = "/opt/xpressmp_8.4/bin"
os.environ['LD_LIBRARY_PATH'] = os.environ['XPRESSDIR']+"/lib:"+os.environ['LD_LIBRARY_PATH']
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['PYTHONPATH']
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.environ['CLASSPATH']
os.environ['CLASSPATH'] =os.environ['XPRESSDIR']+"/lib/xprm.jar:"+os.environ['CLASSPATH']
os.environ['PATH'] =os.environ['XPRESSDIR']+"/bin:"+os.environ['PATH']


from leagues import settings
settings.DATABASES['default']['NAME'] = PROJECT_PATH+'/db.sqlite3'

import django
django.setup()

from scheduler.models import *
from pulp import *


import xpress as xp
xp.controls.outputlog = 1



scenario = Scenario.objects.get(id=32)


# %%

teams = Team.objects.filter(season=scenario.season,active=True).order_by('position')
team_ids = list(teams.values_list('id',flat=True))


getTeamByID = {
    t.id:t for t in teams
}

# %%

pot = {}
teams_in_pot = {}
for i in teams.values_list('pot',flat=True).distinct():
    pot[i] = teams.filter(pot=i)
    teams_in_pot[i] = list(teams.filter(pot=i).values_list('id',flat=True))



# %%


requirements =  GameRequirement.objects.filter(scenario=scenario)

gamereqs = []
for req in requirements:
    gamereqs.append((req.team1.id,req.team2.id))

# directed version
# requirement = {
#     1:[1,-1,2,-2,3,-3,4,-4],
#     2:[1,-1,2,-2,3,-3,4,-4],
#     3:[1,-1,2,-2,3,-3,4,-4],
#     4:[1,-1,2,-2,3,-3,4,-4],
# }
# undirected version
requirement = {
    1:{
        1:2,
        2:2,
        3:2,
        4:2,
    },
    2:{
        1:2,
        2:2,
        3:2,
        4:2,
    },
    3:{
        1:2,
        2:2,
        3:2,
        4:2,
    },
    4:{
        1:2,
        2:2,
        3:2,
        4:2,
    },
}


# %%
# model = LpProblem("Draws", LpMinimize)

# x = {(t1, t2): LpVariable('x_'+str(t1)+'_'+str(t2), lowBound=0, upBound=1, cat=LpInteger) for t1 in teams for t2 in teams if t1 != t2 and t1.country != t2.country}

# # REQUIREMENTS
# for t in teams:
#     for r,val in requirement[t.pot].items():
#         # if r > 0:
#         #     model += lpSum(x[t,t2] for t2 in pot[r] if (t,t2) in x.keys()) == 1, f'home_{t.id}_pot_{r}'
#         # else:
#         #     model += lpSum(x[t2,t] for t2 in pot[-r] if (t,t2) in x.keys()) == 1, f'away_{t.id}_pot_{r}'
#         model += lpSum(x[t,t2] + x[t2,t] for t2 in pot[r] if (t,t2) in x.keys()) == val, f'undirected_{t.id}_pot_{r}'

# for t1,t2 in x.keys():
#     model += x[t1,t2]+x[t2,t1] <= 1, f'play_once_{t1.id}_{t2.id}'

# model += lpSum(random.uniform(0,1)*x[key] for key in x.keys())
# model.solve()

# # %%
# gamereqs = []
# for key in x.keys():
#     if x[key].value() > 0 :
#         gamereqs.append((key[0].id,key[1].id))


# %%


# START COMPUTING SCHEDULE

nRounds = 8
rounds = range(1,nRounds+1)




# %%

#  MODEL WITH PATTERNS

# pos_patterns = [
#     [1,0,1,1,0,0,1,0 ],
#     [1,0,1,0,1,0,1,0 ],
#     [1,0,1,0,1,0,0,1 ],
#     [1,0,1,0,0,1,1,0 ],
#     [1,0,1,0,0,1,0,1 ],
#     [1,0,0,1,1,0,1,0 ],
#     [1,0,0,1,1,0,0,1 ],
#     [1,0,0,1,0,1,1,0 ],
#     [1,0,0,1,0,1,0,1 ],
# ]

# # add reverse patterns (all those starting with 0,1 )
# pos_patterns+=[ [ 1-p[i] for i in range(8)] for p in pos_patterns ]


# patterns = {
#     i:p for i,p in enumerate(pos_patterns)
# }
# model = xp.problem(name='Patterns', sense=xp.minimize)

# x = {}
# assignPattern = {}
# for r in rounds:
#     for game in gamereqs:
#         x[r, game[0], game[1]] = xp.var(ub=1, vartype=xp.integer)
#         x[r, game[1], game[0]] = xp.var(ub=1, vartype=xp.integer)
# for t in team_ids:
#     for p in patterns:
#         assignPattern[t,p] = xp.var(ub=1, vartype=xp.integer)


# model.addVariable(x)
# model.addVariable(assignPattern)

# for (t1,t2) in gamereqs:
#     model.addConstraint(xp.Sum([x[r,t1,t2]+x[r,t2,t1] for r in rounds]) == 1)

# for t in team_ids:
#     for r in rounds:
#         model.addConstraint(xp.Sum([x[r,t,t2]+x[r,t2,t] for t2 in team_ids if (r,t,t2) in x.keys()]) == 1)
#         model.addConstraint(xp.Sum([x[r,t,t2] for t2 in team_ids if (r,t,t2) in x.keys()]) <= xp.Sum([assignPattern[t,p] for p in patterns if patterns[p][r-1] == 1]))
#     model.addConstraint(xp.Sum([assignPattern[t,p] for p in patterns]) == 1)

#     for p in pot:
#         model.addConstraint(xp.Sum([x[r,t,t2] for r in rounds for t2 in team_ids if (r,t,t2) in x.keys() and t2 in teams_in_pot[p]]) == 1)


# =====>>> NOT WORKING WELL

# %%

#  MODEL WITH HOME
model = xp.problem(name='HomeAssignments', sense=xp.minimize)

x = {}
home = {}
for r in rounds:
    for game in gamereqs:
        x[r, game[0], game[1]] = xp.var(ub=1, vartype=xp.integer)
        x[r, game[1], game[0]] = xp.var(ub=1, vartype=xp.integer)
    for t in team_ids:
        home[r,t] = xp.var(ub=1, vartype=xp.integer)

model.addVariable(x)
model.addVariable(home)

# each game has to be played
for (t1,t2) in gamereqs:
    model.addConstraint(xp.Sum([x[r,t1,t2]+x[r,t2,t1] for r in rounds]) == 1)

for t in team_ids:
    for r in rounds:
        # each team plays once in each round
        model.addConstraint(xp.Sum([x[r,t,t2]+x[r,t2,t] for t2 in team_ids if (r,t,t2) in x.keys()]) == 1)
        # couple homes
        model.addConstraint(home[r,t] == xp.Sum([x[r,t,t2] for t2 in team_ids if (r,t,t2) in x.keys()]))
    
    # structural (home) requirements
    for r in range(1,nRounds-1):
        model.addConstraint(xp.Sum([home[r2,t] for r2 in range(r,r+3)]) <= 2)
        model.addConstraint(xp.Sum([1-home[r2,t] for r2 in range(r,r+3)]) <= 2)
    model.addConstraint(xp.Sum([home[r2,t] for r2 in range(1,3)]) == 1)
    model.addConstraint(xp.Sum([home[r2,t] for r2 in range(nRounds-1,nRounds+1)]) == 1)
    
    # play home against each pot
    for p in pot:
        model.addConstraint(xp.Sum([x[r,t,t2] for r in rounds for t2 in team_ids if (r,t,t2) in x.keys() and t2 in teams_in_pot[p]]) == 1)
    
start_time = time()
model.solve()
comp_time = time()-start_time


if model.getProbStatus() != 6:
    print("INFEASIBLE FOUND")

# %%


if model.getProbStatus() == 6:
    home_dict = {}
    away_dict = {}
    for key in x.keys():
        if model.getSolution(x[key]) > 0:
            print(key[0],getTeamByID[key[1]],getTeamByID[key[2]])
            home_dict[key[0],key[1]] = key[2]
            away_dict[key[0],key[2]] = key[1]

    sol = " \
        <style> \
        table, th, td { \
        border: 1px solid black; \
        border-collapse: collapse; \
        } \
        </style> \
    "
    sol += "<table style='border:1px solid black'>\n"
    sol += "<thead>\n"
    sol += "<tr><th></th>"
    for r in rounds:
        sol += f"<th>{r}</th>"
    sol += "</tr>"
    sol += "</thead>\n"
    sol += "<tbody>\n"
    for t in team_ids:
        tname = getTeamByID[t]
        sol += f"<tr><td>{tname}</td>"
        for r in rounds:
            if (r,t) in home_dict.keys():
                opponent = getTeamByID[home_dict[(r,t)]]
                sol += f"<td style='background-color:lightyellow'>{opponent.pot} - {opponent}</td>"
            elif (r,t) in away_dict.keys():
                opponent = getTeamByID[away_dict[(r,t)]]
                sol += f"<td style='background-color:lightsteelblue'>{opponent.pot} - {opponent}</td>"
            else:
                sol += "<td></td>"
        sol += "</tr>"
    sol += "</tbody>\n"
    sol += "</table>\n"
    sol += "<br><br><br>\n"

    with open('draw_schedule.html', 'w') as f:
        f.write(sol)

# %%

games = [(key[1],key[2],key[0]) for key in x.keys() if model.getSolution(x[key]) > 0]
    # %%
