# %%
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 csv
from multiprocessing import Pool, cpu_count
import random
import time
import pulp
from pulp import lpSum, value, XPRESS, GUROBI, PULP_CBC_CMD

import xpress as xp
# xp.controls.outputlog = 0



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

# %%

# teamObjects = Team.objects.filter(season=scenario.season,active=True).order_by('pot','country')
teamObjects = Team.objects.filter(season=scenario.season,active=True)
teams = teamObjects.values('id','country','pot','name')

getTeamById = {}
for t in teamObjects:
    getTeamById[t.id] = f"({t.pot}) {t.name}"


countries = list(set(teamObjects.values_list('country', flat=True)))
teams_from_country = {
    c:[t for t in teams if t['country']==c] for c in countries 
}

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

teams = list(teams)





fixed_games = [(3940, 3894), (3933, 3940), (3940, 3937), (3765, 3940), (3940, 3895), (3700, 3940), (3940, 3696), (3925, 3940), (3702, 3935), (3894, 3702), (3702, 3926), (3937, 3702), (3702, 3700), (3758, 3702), (3702, 3699), (3757, 3702), (3932, 3762), (3732, 3932), (3932, 3938), (3761, 3932), (3932, 3730), (3701, 3932), (3932, 3870), (3853, 3932), (3764, 3933), (3935, 3764), (3764, 3936), (3898, 3764), (3764, 3756), (3928, 3764), (3764, 3925), (3904, 3764), (3762, 3732), (3762, 3761), (3930, 3762), (3762, 3701), (3760, 3762), (3762, 3697), (3698, 3762), (3732, 3765), (3926, 3732), (3732, 3928), (3730, 3732), (3732, 3698), (3870, 3732), (3894, 3930), (3938, 3894), (3894, 3758)]


# fixed_games = [(3702, 3935), (3702, 3926), (3702, 3700), (3702, 3699), (3764, 3933), (3764, 3936), (3764, 3756), (3764, 3925), (3940, 3894), (3940, 3937), (3940, 3895), (3940, 3696), (3762, 3732), (3762, 3761), (3762, 3701), (3762, 3697), (3894, 3702), (3894, 3930), (3894, 3758), (3894, 3904), (3933, 3940), (3933, 3734), (3933, 3771), (3933, 3853), (3935, 3764), (3935, 3898), (3935, 3760), (3935, 3757), (3932, 3762), (3932, 3938), (3932, 3730), (3932, 3870), (3732, 3932), (3732, 3765), (3732, 3928), (3732, 3698), (3938, 3894), (3938, 3930), (3938, 3730), (3938, 3697), (3761, 3932), (3761, 3938), (3761, 3895), (3761, 3904), (3898, 3764), (3898, 3761), (3898, 3700), (3898, 3696), (3926, 3732), (3926, 3734), (3926, 3701), (3926, 3699), (3936, 3933), (3936, 3765), (3936, 3758), (3936, 3698), (3734, 3935), (3734, 3936), (3734, 3928), (3734, 3925), (3930, 3762), (3930, 3926), (3930, 3756), (3930, 3853), (3937, 3702), (3937, 3898), (3937, 3771), (3937, 3757), (3765, 3940), (3765, 3937), (3765, 3760), (3765, 3870), (3758, 3702), (3758, 3926), (3758, 3756), (3758, 3925), (3756, 3894), (3756, 3936), (3756, 3701), (3756, 3698), (3771, 3935), (3771, 3898), (3771, 3700), (3771, 3697), (3895, 3933), (3895, 3930), (3895, 3758), (3895, 3699), (3701, 3932), (3701, 3761), (3701, 3771), (3701, 3870), (3760, 3762), (3760, 3734), (3760, 3895), (3760, 3757), (3928, 3764), (3928, 3938), (3928, 3760), (3928, 3904), (3730, 3732), (3730, 3937), (3730, 3928), (3730, 3696), (3700, 3940), (3700, 3765), (3700, 3730), (3700, 3853), (3904, 3764), (3904, 3898), (3904, 3771), (3904, 3696), (3925, 3940), (3925, 3930), (3925, 3701), (3925, 3697), (3698, 3762), (3698, 3938), (3698, 3758), (3698, 3699), (3699, 3935), (3699, 3937), (3699, 3760), (3699, 3853), (3696, 3894), (3696, 3765), (3696, 3895), (3696, 3925), (3853, 3932), (3853, 3936), (3853, 3928), (3853, 3757), (3697, 3933), (3697, 3761), (3697, 3756), (3697, 3904), (3757, 3702), (3757, 3734), (3757, 3730), (3757, 3870), (3870, 3732), (3870, 3926), (3870, 3700), (3870, 3698)]


# sol = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
# sol += " \
# <style>     \
#     table, th, td {     \
#             border: 1px solid black;     \
#             border-collapse: collapse;     \
#             text-align: center;     \
#             min-width:40px;     \
#             padding:3px;     \
#             margin: 3px;     \
#             font-family : Arial;\
#     }     \
#     h1 {\
#         font-family : Arial;\
#     }\
# \
#     #etable td:nth-child(10),#etable th:nth-child(10) { border-right: 5px solid black; }\
#     #etable td:nth-child(19),#etable th:nth-child(19) { border-right: 5px solid black; }\
#     #etable td:nth-child(28),#etable th:nth-child(28) { border-right: 5px solid black; }\
#     tr:nth-child(9) { border-bottom: 5px solid black; }\
#     tr:nth-child(18) { border-bottom: 5px solid black; }\
#     tr:nth-child(27) { border-bottom: 5px solid black; }\
# </style> \
# "
# sol += "</head><body>"

# sol += "<table id='etable' style='border:5px solid black'>\n"
# sol += "<thead>\n"
# sol += "<tr>"
# sol += "<th></th>"
# sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot A</th>"
# sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot B</th>"
# sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot C</th>"
# sol += "<th colspan=9>Pot D</th>"
# sol += "</tr>"
# sol += "<tr>\n"
# sol += f"<th></th>\n"
# # for o in order:
# for t in teams:
#     # t = getTeamByName[o]
#     sol += f"<th>{t['name']}({t['country']})</th>\n"
# sol += "</tr>\n"
# sol += "</thead>\n"
# sol += "<tbody>\n"
# # for o1 in order:
# for t1 in teams:
#     # t1 = getTeamByName[o1]
#     sol += "<tr>\n"
#     sol += f"<td>{t1['name']}({t1['country']})</td>"
#     # for o2 in order:
#     for t2 in teams:
#         # t2 = getTeamByName[o2]
#         # val = stats[t1,t2]
#         if (t1['id'],t2['id']) in fixed_games:
#             sol += f"<td>{t2['country']}</td>"
#         elif (t2['id'],t1['id']) in fixed_games:
#             sol += f"<td>@{t2['country']}</td>"
#         else:
#             sol += f"<td></td>"
#     sol += "</tr>\n"

# sol += "</tbody>\n"
# sol += "</table>\n"



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




# %%



def check_feasible(fixed_games):

    model = pulp.LpProblem(f"Draws", pulp.LpMinimize)
    xp_model = xp.problem(name='Draws', sense=xp.minimize)
    xp_model.setControl('outputlog', 1)
    xp_model.setControl('presolve',0)
    x = {}
    xp_x = {}
    for t1 in teams:
        for t2 in teams:
            if t1['country'] != t2['country']:
                x[t1['id'], t2['id']] = pulp.LpVariable('x_'+str(t1['id'])+'_'+str(t2['id']),lowBound=0, upBound=1, cat=pulp.LpInteger)
                xp_x[t1['id'], t2['id']] = xp.var(ub=1, vartype=xp.integer)

    xp_model.addVariable(xp_x)



    # REQUIREMENTS
    for t in teams:
        for r in range(1,5):
            xp_model.addConstraint(xp.Sum(xp_x[t['id'],t2['id']] for t2 in pot[r] if (t['id'],t2['id']) in xp_x.keys()) == 1)
            xp_model.addConstraint(xp.Sum(xp_x[t2['id'],t['id']] for t2 in pot[r] if (t2['id'],t['id']) in xp_x.keys()) == 1)
            model += lpSum(x[t['id'],t2['id']] for t2 in pot[r] if (t['id'],t2['id']) in x.keys()) == 1
            model += lpSum(x[t2['id'],t['id']] for t2 in pot[r] if (t2['id'],t['id']) in x.keys()) == 1

        
        for c in countries:
            if c != t['country']:
                xp_model.addConstraint(xp.Sum(xp_x[t['id'],t2['id']]+xp_x[t2['id'],t['id']] for t2 in teams_from_country[c]) <= 2)
                model += lpSum(x[t['id'],t2['id']]+x[t2['id'],t['id']] for t2 in teams_from_country[c]) <= 2


    # FIXATIONS
    for (t1,t2) in fixed_games:
        xp_model.addConstraint(xp_x[t1,t2] == 1)
        model += x[t1,t2] == 1



    for (t1,t2) in xp_x.keys():
        xp_model.addConstraint(xp_x[t1,t2] + xp_x[t2,t1] <= 1)
    for (t1,t2) in x.keys():
        model += x[t1,t2] + x[t2,t1] <= 1

    # model += lpSum(random.uniform(0,1)*x[key] for key in x.keys())
    model.writeMPS('pulp.mps',rename=True)
    model.solve(XPRESS(msg=1))

    # xp_model.solve()
    # print(model.status)
    # if model.status in [-1,-2]:
    #     print("ERROR")
    # else:
    #     print("SUCCESS")


    #     games = []
    #     for key in x.keys():
    #         if x[key].value() != 0:
    #             # print(key,xp_model.getSolution(xp_x[key]))
    #             games.append(key)


    #     sol = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
    #     sol += " \
    #     <style>     \
    #         table, th, td {     \
    #                 border: 1px solid black;     \
    #                 border-collapse: collapse;     \
    #                 text-align: center;     \
    #                 min-width:40px;     \
    #                 padding:3px;     \
    #                 margin: 3px;     \
    #                 font-family : Arial;\
    #         }     \
    #         h1 {\
    #             font-family : Arial;\
    #         }\
    #     \
    #         #etable td:nth-child(10),#etable th:nth-child(10) { border-right: 5px solid black; }\
    #         #etable td:nth-child(19),#etable th:nth-child(19) { border-right: 5px solid black; }\
    #         #etable td:nth-child(28),#etable th:nth-child(28) { border-right: 5px solid black; }\
    #         tr:nth-child(9) { border-bottom: 5px solid black; }\
    #         tr:nth-child(18) { border-bottom: 5px solid black; }\
    #         tr:nth-child(27) { border-bottom: 5px solid black; }\
    #     </style> \
    #     "

    #     sol += "<table id='etable' style='border:5px solid black'>\n"
    #     sol += "<thead>\n"
    #     sol += "<tr>"
    #     sol += "<th></th>"
    #     sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot A</th>"
    #     sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot B</th>"
    #     sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot C</th>"
    #     sol += "<th colspan=9>Pot D</th>"
    #     sol += "</tr>"
    #     sol += "<tr>\n"
    #     sol += f"<th></th>\n"
    #     # for o in order:
    #     for t in teams:
    #         # t = getTeamByName[o]
    #         sol += f"<th>{getTeamById[t['id']]}</th>\n"
    #     sol += "</tr>\n"
    #     sol += "</thead>\n"
    #     sol += "<tbody>\n"
    #     # for o1 in order:
    #     for t1 in teams:
    #         # t1 = getTeamByName[o1]
    #         sol += "<tr>\n"
    #         sol += f"<td>{getTeamById[t1['id']]}</td>"
    #         # for o2 in order:
    #         for t2 in teams:
    #             # t2 = getTeamByName[o2]
    #             # val = stats[t1,t2]
    #             if (t1['id'],t2['id']) in games:
    #                 sol += f"<td>{t2['country']}</td>"
    #             elif (t2['id'],t1['id']) in games:
    #                 sol += f"<td>@{t2['country']}</td>"
    #             else:
    #                 sol += f"<td></td>"
    #         sol += "</tr>\n"

    #     sol += "</tbody>\n"
    #     sol += "</table>\n"



    #     with open(f'debug_pulp.html', 'w') as f:
    #         f.write(sol)
        
    # print("\n\n\n\n")
    # # model.writeMPS('pulp.mps',rename=True)
    # # xp_model.write('xpress.lp','lps')
    # xp_model.solve()



    # if xp_model.getProbStatus() != 6:
    #     print("ERROR")
    #     # print("INFEASIBLE FOUND")
    # else:
    #     print("SUCCESS")

    #     games = []
    #     for key in xp_x.keys():
    #         if xp_model.getSolution(xp_x[key]) != 0:
    #             # print(key,xp_model.getSolution(xp_x[key]))
    #             games.append(key)

    #     print(len(games))

    #     sol = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
    #     sol += " \
    #     <style>     \
    #         table, th, td {     \
    #                 border: 1px solid black;     \
    #                 border-collapse: collapse;     \
    #                 text-align: center;     \
    #                 min-width:40px;     \
    #                 padding:3px;     \
    #                 margin: 3px;     \
    #                 font-family : Arial;\
    #         }     \
    #         h1 {\
    #             font-family : Arial;\
    #         }\
    #     \
    #         #etable td:nth-child(10),#etable th:nth-child(10) { border-right: 5px solid black; }\
    #         #etable td:nth-child(19),#etable th:nth-child(19) { border-right: 5px solid black; }\
    #         #etable td:nth-child(28),#etable th:nth-child(28) { border-right: 5px solid black; }\
    #         tr:nth-child(9) { border-bottom: 5px solid black; }\
    #         tr:nth-child(18) { border-bottom: 5px solid black; }\
    #         tr:nth-child(27) { border-bottom: 5px solid black; }\
    #     </style> \
    #     "

    #     sol += "<table id='etable' style='border:5px solid black'>\n"
    #     sol += "<thead>\n"
    #     sol += "<tr>"
    #     sol += "<th></th>"
    #     sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot A</th>"
    #     sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot B</th>"
    #     sol += "<th colspan=9 style='border-right: 5px solid black;'>Pot C</th>"
    #     sol += "<th colspan=9>Pot D</th>"
    #     sol += "</tr>"
    #     sol += "<tr>\n"
    #     sol += f"<th></th>\n"
    #     # for o in order:
    #     for t in teams:
    #         # t = getTeamByName[o]
    #         sol += f"<th>{getTeamById[t['id']]}</th>\n"
    #     sol += "</tr>\n"
    #     sol += "</thead>\n"
    #     sol += "<tbody>\n"
    #     # for o1 in order:
    #     for t1 in teams:
    #         # t1 = getTeamByName[o1]
    #         sol += "<tr>\n"
    #         sol += f"<td>{getTeamById[t1['id']]}</td>"
    #         # for o2 in order:
    #         for t2 in teams:
    #             # t2 = getTeamByName[o2]
    #             # val = stats[t1,t2]
    #             if (t1['id'],t2['id']) in games:
    #                 sol += f"<td>{t2['country']}</td>"
    #             elif (t2['id'],t1['id']) in games:
    #                 sol += f"<td>@{t2['country']}</td>"
    #             else:
    #                 sol += f"<td></td>"
    #         sol += "</tr>\n"

    #     sol += "</tbody>\n"
    #     sol += "</table>\n"



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




# def check_feasible_2(fixed_games):
#     model = xp.problem(name='Draws', sense=xp.minimize)
#     model.setControl ('outputlog', 1)

#     x = {}
#     for t1 in teams:
#         for t2 in teams:
#             if t1['country'] != t2['country']:
#                 x[t1['id'], t2['id']] = xp.var(ub=1, vartype=xp.integer)

#     model.addVariable(x)

#     # REQUIREMENTS
#     for t in teams:
#         for r in range(1,5):
#             model.addConstraint(xp.Sum(x[t['id'],t2['id']] for t2 in pot[r] if (t['id'],t2['id']) in x.keys()) == 1)
#             model.addConstraint(xp.Sum(x[t2['id'],t['id']] for t2 in pot[r] if (t2['id'],t['id']) in x.keys()) == 1)
#         for c in countries:
#             if c != t['country']:
#                 model.addConstraint(xp.Sum(x[t['id'],t2['id']]+x[t2['id'],t['id']] for t2 in teams_from_country[c]) <= 2)


#     # FIXATIONS
#     for (t1,t2) in fixed_games:
#         # print("FIXING",t1,t2)
#         model.addConstraint(x[t1,t2] == 1)

#     for (t1,t2) in x.keys():
#         model.addConstraint(x[t1,t2] + x[t2,t1] <= 1)

    
#     tt =time.time()
#     model.solve()
#     comp_time = time.time()-tt


#     if model.getProbStatus() != 6:
#         # print("INFEASIBLE FOUND")
#         return False, comp_time
#     else:
#         return True, comp_time
    

check_feasible(fixed_games)

exit()


# %%


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

x = {}
for t1 in teams:
    for t2 in teams:
        if t1['country'] != t2['country']:
            x[t1['id'], t2['id']] = xp.var(ub=1, vartype=xp.integer)

model.addVariable(x)

# REQUIREMENTS
for t in teams:
    for r in range(1,5):
        model.addConstraint(xp.Sum(x[t['id'],t2['id']] for t2 in pot[r] if (t['id'],t2['id']) in x.keys()) == 1)
        model.addConstraint(xp.Sum(x[t2['id'],t['id']] for t2 in pot[r] if (t2['id'],t['id']) in x.keys()) == 1)
    for c in countries:
        if c != t['country']:
            model.addConstraint(xp.Sum(x[t['id'],t2['id']]+x[t2['id'],t['id']] for t2 in teams_from_country[c]) <= 2)

for (t1,t2) in x.keys():
    model.addConstraint(x[t1,t2] + x[t2,t1] <= 1)

def check_feasible_fix(fixed_games):
    # FIXATIONS
    # for key in x.keys():
    #     if key in fixed_games:
    #         # x[key].lb = 1
    #         model.chgbounds([x[key]],['L'],[1])
    #     else:
    #         # x[key].lb = 0
    #         model.chgbounds([x[key]],['L'],[0])
    
    reset_bounds = [key for key in x.keys() if key not in fixed_games]

    model.chgbounds([x[key] for key in fixed_games],['L' for _ in range(len(fixed_games))],[1 for _ in range(len(fixed_games))])
    model.chgbounds([x[key] for key in reset_bounds],['L' for _ in range(len(reset_bounds))],[0 for _ in range(len(reset_bounds))])

    # tt =time.time()
    model.solve()
    # comp_time = time.time()-tt

    if model.getProbStatus() != 6:
        # print("INFEASIBLE FOUND")
        # return False, comp_time
        return False
    else:
        # return True, comp_time
        return True
    


check_feasible_fix(fixed_games)
exit()
    
# def ucl24_random_games(team_to_check, pots_to_check, oldgames):
#     teamObjects = Team.objects.filter(season=scenario.season,active=True)
#     teams = [t.id for t in teamObjects]
#     t_country = {t.id : t.country for t in teamObjects}
#     t_name = {t.id : t.name for t in teamObjects}
#     t_pot = {t.id : t.pot for t in teamObjects}
#     countries = sorted(list(set(t_country.values())))
#     pots = sorted(list(set(t_pot.values())))

#     max_opponents_from_same_country=2

#     givenHome = { (t,p) : False for t in teams for p in pots }
#     givenAway = { (t,p) : False for t in teams for p in pots }
#     gamesAgainstCountry = { (t,c) : 0 for t in teams for c in countries }

#     for (t1,t2) in oldgames:
#         givenHome[t1,t_pot[t2]]=t2
#         givenAway[t2,t_pot[t1]]=t1
#         gamesAgainstCountry[(t1,t_country[t2])]+=1
#         gamesAgainstCountry[(t2,t_country[t1])]+=1

#     no_solution_found = True

#     possHomeOpponents={}
#     possAwayOpponents={}
#     for p in pots_to_check:
#         print( "POT " , p)
#         possOpponents1 = [ t for t in teams if t_country[t]!=t_country[team_to_check] and t_pot[t]==p and t!=givenAway[team_to_check,p] ]
#         possOpponents = [ t for t in possOpponents1 if gamesAgainstCountry[(team_to_check,t_country[t])]<2 and gamesAgainstCountry[(t,t_country[team_to_check])]<2]
#         if givenHome[team_to_check,p]:
#             possHomeOpponents[p]= [givenHome[team_to_check,p]]
#         else:
#             possHomeOpponents[p] = [ t for t in possOpponents if not givenAway[t,t_pot[team_to_check]] ]
#         if givenAway[team_to_check,p]:
#             possAwayOpponents[p]= [givenAway[team_to_check,p]]
#         else:
#             possAwayOpponents[p] = [ t for t in possOpponents if not givenHome[t,t_pot[team_to_check]]]

#     while no_solution_found:
#         newgames = []
#         for p in pots_to_check:
#             random_home= random.choice(possHomeOpponents[p])
#             random_away= random.choice(possAwayOpponents[p])
#             print (p,"-> " , random_home==random_away, t_name[random_home], "\t ", t_name[random_away] )
#             newgames+=[(team_to_check,random_home), (random_away,team_to_check) ]
#         if random_home!=random_away and check_feasible(oldgames+newgames):    
#             no_solution_found = False

#     newgames = [gm for gm in newgames if gm not in oldgames]
#     return newgames


# %%



def simulate_draws(filename,n):

    print("RUNNING ASYNC",filename)

    for i in range(1, n):
        if i % 100 == 0:
            print("RUNNING ASYNC",filename,i)    
        # start_time = time.time()      
        # n_computations = 0  
        # check_time = 0
        # total_comp_time = 0


        possible_opps = {}
        for pos in range(8):
            p = pos//2+1
            teams_from_pot = list(teamObjects.filter(pot=p).values('id','country'))
            possible_opps[pos] = {
                t['id']: [t2['id'] for t2 in teams_from_pot if t2['country'] != t['country']] for t in teams
            }

        sol_opps = {
            (t['id'],p):None
            for t in teams for p in range(8)
        }
        fixed_games = []
        feasible = True

        for p in range(1,5): 
            currentPot = list(teamObjects.filter(pot=p).values_list('id', flat=True))

            while(feasible and currentPot):    
                new_team = currentPot.pop(random.randint(0,len(currentPot)-1))
                for current_pos in range(8):
                    while (feasible and sol_opps[new_team,current_pos] == None):
                        try:
                            new_opponent = random.choice(possible_opps[current_pos][new_team])
                        except:
                            feasible = False
                            print("INFEASIBLE")
                            print(sol_opps)
                            print(fixed_games)
                            print(possible_opps)
                            print(new_team,current_pos)
                            print(possible_opps[current_pos][new_team])


                            exit()
                            
                        if sol_opps[new_opponent,(2*p-1)-(current_pos % 2)] == None:
                            new_game = (new_team,new_opponent) if current_pos % 2 == 0 else (new_opponent,new_team)
                            # n_computations += 1
                            # tt = time.time()
                            # check, comp_time = check_feasible_fix(fixed_games+[new_game])
                            # check_time += time.time()-tt
                            # total_comp_time += comp_time
                            if check_feasible_fix(fixed_games+[new_game]):
                                sol_opps[new_team,current_pos] = new_opponent
                                sol_opps[new_opponent,(2*p-1)-(current_pos % 2)] = new_team
                                fixed_games.append(new_game)
                                if new_opponent in possible_opps[(2*p-1)-(current_pos % 2)][new_team]:
                                    possible_opps[(2*p-1)-(current_pos % 2)][new_team].remove(new_opponent)    
                            possible_opps[current_pos][new_team].remove(new_opponent)                  
                        else:
                            possible_opps[current_pos][new_team].remove(new_opponent)


        # for p in [1,2,3,4]: 
        # # for p in [4,3,2,1]: 
        #     currentPot = list(teamObjects.filter(pot=p).values_list('id', flat=True))

        #     while(feasible and currentPot):    
        #         # Draw Team
        #         new_team = currentPot.pop(random.randint(0,len(currentPot)-1))
        #         draw_index_dict[new_team] = draw_index
        #         draw_index += 1

        #         # print("New team",new_team,getTeamById[new_team])                        
        #         for pos in range(8):
        #             # Skip if already drawn
        #             if sol_opps[new_team,pos]:
        #                 continue
        #             #  Update possible opponents     
        #             opponent_pool = []           
        #             for new_opponent in possible_opps[pos][new_team]:
        #                 if sol_opps[new_opponent,(2*p-1)-(pos % 2)] != None:
        #                     continue
        #                     # print(f"---> ALREADY DRAWN {pos}: {getTeamById[new_opponent]}")                            
        #                 else:
        #                     new_game = (new_team,new_opponent) if pos % 2 == 0 else (new_opponent,new_team)
        #                     n_computations += 1
        #                     tt = time.time()
        #                     feasible = check_feasible(fixed_games+[new_game])
        #                     comp_time += time.time()-tt
        #                     if feasible:
        #                         opponent_pool.append(new_opponent)
        #                     else:
        #                         # print(f"---> CANNOT DRAW {pos}: {[getTeamById[ttt] for ttt in new_game]}")                            
        #                         num_combinatorial_clashes[new_team,pos] += 1
        #             num_possible_opps[new_team,pos] = len(opponent_pool)
        #             # Draw random opponent                
        #             new_opponent = random.choice(opponent_pool)
        #             new_game = (new_team,new_opponent) if pos % 2 == 0 else (new_opponent,new_team)
        #             # if not check_feasible(fixed_games+[new_game]):
        #             #     print("INFEASIBLE")
        #             #     print("POSSOPS AFTER",[getTeamById[tt] for tt in possible_opps[pos][new_team]])
        #             #     print(f"{p} - {pos} - {getTeamById[sol_opps[new_opponent,(2*p-1)-(pos % 2)]]}")
        #             #     feasible = False
        #             #     break
                        
        #             sol_opps[new_team,pos] = new_opponent
        #             sol_opps[new_opponent,(2*p-1)-(pos % 2)] = new_team
        #             if pos % 2 == 0:
        #                 possible_opps[pos+1][new_team].remove(new_opponent)                               
        #             fixed_games.append(new_game)


        # print("COMPUTATIONS",n_computations)
        # print("TIME\t",time.time()-start_time)
        # print("CHECK\t",check_time)
        # print("COMP\t",total_comp_time)
        with open(filename+'.csv', "a") as f:
            for t in teams:
                f.write(f"{i},{t['id']},{';'.join([str(sol_opps[t['id'],p]) for p in range(8)])}\n")






            # for game in fixed_games:
            #     if game[0] == new_team or game[1] == new_team:
            #         print("\t"," vs ".join([getTeamById[tt] for tt in game]))
            # print(f"--- > {draw_index_dict[new_team]}")
            # for pos in range(8):
            #     print(f"--- > {pos} - {num_possible_opps[new_team,pos]}")

            # iterate over h/a-encounters
            # for current_pos in range(8):
            #     while (sol_opps[new_team,current_pos] == None):
            #         # print(possible_opps[current_pos][new_team])
            #         #  draw opponent
            #         new_opponent = random.choice(possible_opps[current_pos][new_team])
            #         print("\tNEW OPP",new_opponent,getTeamById[new_opponent])
            #         new_game = (new_team,new_opponent) if current_pos % 2 == 0 else (new_opponent,new_team)
            #         if check_feasible(fixed_games+[new_game]):
            #             # print("FEASIBLE",new_game,[getTeamById[tt] for tt in new_game])
            #             sol_opps[new_team,current_pos] = new_opponent
            #             sol_opps[new_opponent,(2*p-1)-(current_pos % 2)] = new_team
            #             fixed_games.append(new_game)
            #             possible_opps[current_pos][new_team].remove(new_opponent)
            #         else:                      
            #             possible_opps[current_pos][new_team].remove(new_opponent)     
# %%


# # SOLUTION
# for g in fixed_games:
#     print(getTeamById[g[0]],getTeamById[g[1]])






# n = sys.maxsize

# pool = Pool()
# result = {}
# answer = {}
# n_threads = cpu_count()
# # n_threads = 1

# for cpu in range(n_threads):
#     result[cpu] = pool.apply_async(simulate_draws, args=(f'thread_{cpu}_pot_by_pot', n,))

# for cpu in range(n_threads):
#     answer[cpu] = result[cpu].get()


# %%
n = sys.maxsize
simulate_draws('test', n)












# %%


