from cvxopt import matrix, solvers
import numpy as np

import torch
import torch.nn as nn
import numpy as np
from deepset import *
import numpy as np
import copy
import pickle

def fhoi_compute_score(model, idxs, absl=False):
    indiv_score = np.sum(model.weight.bias.detach().numpy()[idxs])
    team_score = 0.0
    mat = model.weight.weight.detach().numpy()
    for i in idxs:
        for j in idxs:
            w = mat[i,j]
            if absl: w = np.abs(w)
            if i == j: indiv_score += w
            else: team_score += w
    return indiv_score + team_score

def get_idx(names):
    return np.array([int(ch_id[x]) for x in names])

#######################################################################

#COMPUTE THE CORE

def make_powerset(size):

    mat = [[0], [1]]
    for i in range(size - 1):
        mat = [x + [0] for x in mat] + [x + [1] for x in mat]
    mat.pop(0)
    mat.pop()
    mat = [x + [1] for x in mat]
    #mat = [x + [-1] for x in mat]
    return mat

'''
LEAST CORE
'''
def compute_core(team_idx, model, score_fn):

    team_size = len(team_idx)

    powerset = make_powerset(team_size)
    powerset.append([1] * team_size + [0])
    powerset.append([-1] * team_size + [0])
    powerset = np.array(powerset).astype("double")
    
    vs = []
    for i in range(len(powerset) - 1):
        subset = powerset[i][:-1]
        sub_team = team_idx[subset > 0]
        vs.append(score_fn(model, sub_team))
    vs.append(-vs[-1])
    vs = np.array(vs).astype("double")
    
    c = np.zeros(team_size + 1).astype("double")
    c[-1]  = 1
    
    #sol=solvers.lp(matrix(-c), matrix(-powerset), matrix(-np.array(vs)))
    sol=solvers.lp(matrix(c), matrix(-powerset), matrix(-vs))

    if sol["x"] is None: return 
    
    #return list(zip(list(sol["x"]), [id_ch[str(j)] for j in team_idx]))
    return list(sol["x"])[:-1]

#######################################################################

import itertools

def compute_shapley(player_idx, player_list, model, score_fn):
    marginal_value = []
    for perm in itertools.permutations(player_list):
        i = perm.index(player_idx)
        team_without = list(perm[:i])
        without_score = 0 if len(team_without) == 0 else score_fn(model, team_without)
        team_with = list(perm[:i+1])
        with_score = score_fn(model, team_with)
        
        marginal_value.append(with_score - without_score)
    
    return np.average(marginal_value)

#[(name, compute_shapley(name, player_list, model)) for name in player_list]

#######################################################################

#compute solution concept for every starting lineup a part of

def post_process(scores):
    scores = [(i, np.average(s)) for i,s in list(scores.items())]
    scores.sort(key=lambda x: x[1])
    scores = [(id_ch[str(i)], score) for i,score in scores]
    return scores

