import os
import sys
import pandas as pd
import numpy as np
from numpy.random import poisson, uniform
from numpy import mean
import time
import math

def geo_average(values, weights = None):
    values = np.array(values)
    if weights is None:
        weights = np.ones_like(values)
    else:
        weights = np.array(weights)
    return np.power((np.power(values + 1, weights).prod()), 1/weights.sum()) - 1

po = True

team_homes = pd.read_csv(os.path.join(os.path.split(__file__)[0], 'TeamHomes.csv'), header = None, index_col = 0)
stadium_locs = pd.read_csv(os.path.join(os.path.split(__file__)[0], 'StadiumLocs.csv'), index_col = 0)

teamsheetpath = os.path.join(os.path.split(__file__)[0], 'teamcsvs')

compstat = {'TF': 'TA', 'TA': 'TF', #Dictionary to use to compare team stats with opponent stats
            'CF': 'CA', 'CA': 'CF',
            'CON%F': 'CON%A', 'CON%A': 'CON%F',
            'PF': 'PA', 'PA': 'PF',
            'DGF': 'DGA', 'DGA': 'DGF'}

def get_opponent_stats(opponent, venue): #Gets summaries of statistics for opponent each week
    opponent_stats = {}
    global teamsheetpath, stadium_locs, team_homes
    opp_stats = pd.DataFrame.from_csv(os.path.join(teamsheetpath, opponent + '.csv'))

    opponent_home = team_homes[1][opponent]
    (venue_lat, venue_lng) = stadium_locs.loc[venue, ['Lat', 'Long']]
    (opponent_home_lat, opponent_home_lng) = stadium_locs.loc[opponent_home, ['Lat', 'Long']]
    opponent_reference_distance = geodesic_distance(opponent_home_lat, opponent_home_lng, venue_lat, venue_lng)

    def get_opponent_weight(location):
        return get_travel_weight(location, opponent_home_lat, opponent_home_lng, opponent_reference_distance)

    opp_stats['Weight'] = opp_stats['VENUE'].apply(get_opponent_weight)

    for stat in opp_stats.columns:
        if stat != 'VENUE':
            if stat != 'OPP':
                opponent_stats.update({stat: geo_average(opp_stats[stat], weights = opp_stats['Weight'])})
    opponent_stats.update({'CON%F': float((opp_stats['CF']*opp_stats['Weight']).sum())/(opp_stats['TF']*opp_stats['Weight']).sum()})
    opponent_stats.update({'CON%A': float((opp_stats['CA']*opp_stats['Weight']).sum())/(opp_stats['TA']*opp_stats['Weight']).sum()})
    return opponent_stats

def get_residual_performance(score_df): #Get how each team has done compared to the average performance of their opponents
    global teamsheetpath, team_homes, stadium_locs
    #score_df = pd.DataFrame.from_csv(os.path.join(teamsheetpath, team + '.csv'))
    residual_stats = {}
    score_df['CON%F'] = np.nan
    score_df['CON%A'] = np.nan
    for week in score_df.index:
        opponent_stats = get_opponent_stats(score_df['OPP'][week], score_df['VENUE'][week])
        for stat in opponent_stats:
            if week == score_df.index.tolist()[0]:
                score_df['OPP_' + stat] = np.nan       
            score_df['OPP_' + stat][week] = opponent_stats[stat]
        score_df['CON%F'][week] = float(score_df['CF'][week]) / score_df['TF'][week]
        score_df['CON%A'][week] = float(score_df['CA'][week]) / score_df['TA'][week]
    #print opponent_stats
    for stat in opponent_stats:
        
        if stat == 'Weight':
            continue

        score_df['R_' + stat] = score_df[stat] - score_df['OPP_' + compstat[stat]]
        if stat in ['TF', 'PF', 'DGF', 'TA', 'PA', 'DGA']:
            residual_stats.update({stat: geo_average(score_df['R_' + stat], weights = score_df['Weight'])})
        elif stat == 'CON%F':
            residual_stats.update({stat: (score_df['R_CON%F'].multiply(score_df['TF'])*score_df['Weight']).sum() / (score_df['TF']*score_df['Weight']).sum()})
        elif stat == 'CON%A':
            residual_stats.update({stat: (score_df['R_CON%A'].multiply(score_df['TA'])*score_df['Weight']).sum() / (score_df['TA']*score_df['Weight']).sum()})
    return residual_stats

def get_score(expected_scores): #Get the score for a team based on expected scores
    score = 0
    if expected_scores['T'] > 0:
        tries = poisson(expected_scores['T'])
    else:
        tries = poisson(0.01)
    score = score + 6 * tries
    if expected_scores['P'] > 0:
        fgs = poisson(expected_scores['P'])
    else:
        fgs = poisson(0.01)
    score = score + 3 * fgs
    if expected_scores['DG'] > 0:
        sfs = poisson(expected_scores['DG'])
    else:
        sfs = poisson(0.01)
    score = score + 2 * sfs
    for t in range(tries):
        successful_con_determinant = uniform(0, 1)
        if successful_con_determinant <= expected_scores['CONPROB']:
            score += 2
        else:
            continue
    #if tries >= 4:
    #    bp = True
    #else:
    #    bp = False
    return (score, tries)

def game(team_1, team_2,
         expected_scores_1, expected_scores_2,
         playoff = False): #Get two scores and determine a winner
    (score_1, tr
ies_1) = get_score(expected_scores_1)
    (score_2, tries_2) = get_score(expected_scores_2)

    if tries_1 - tries_2 >= 3:
        bp1 = True
        bp2 = False
    elif tries_2 - tries_1 >= 3:
        bp1 = False
        bp2 = True
    else:
        bp1 = False
        bp2 = False

    if score_1 > score_2:
        win_1 = 1
        win_2 = 0
        draw_1 = 0
        draw_2 = 0
        if bp1:
            
bpw1 = 1
        else:
            bpw1 = 0
        if bp2:
            bpl2 = 1
        else:
            bpl2 = 0
        bpl1 = 0
        bpw2 = 0
        bpd1 = 0
        bpd2 = 0
        lbp1 = 0
        if score_1 - score_2 <= 7:
            lbp2 = 1
        else:
            lbp2 = 0

    elif score_2 > score_1:
        win_1 = 0
        win_2 = 1
        draw_1 = 0
        draw_2 = 0
        if bp1:
            bpl1 = 1
        else:
            bpl1 = 0
        if bp2:
            bpw2 = 1
        else:
            bpw2 = 0
        bpw1 = 0
        bpl2 = 0
        bpd1 = 0
        bpd2 = 0
        lbp2 = 0
        if score_2 - score_1 <= 7:
            lbp1 = 1
        else:
            lbp1 = 0
    else:
        if playoff:
            win_1 = 0.5
            win_2 = 0.5
            draw_1 = 0
            draw_2 = 0
            bpw1 = 0
            bpw2 = 0
            bpd1 = 0
            bpd2 = 0
            bpl1 = 0
            bpl2 = 0
            lbp1 = 0
            lbp2 = 0
        else:
            win_1 = 0
            win_2 = 0
            draw_1 = 1
            draw_2 = 1
            bpw1 = 0
            bpw2 = 0
            bpl1 = 0
            bpl2 = 0
            lbp1 = 0
            lbp2 = 0
        if bp1:
            bpd1 = 1
        else:
            bpd1 = 0
        if bp2:
            bpd2 = 1
        else:
            bpd2 = 0
    summary = {team_1: [win_1, draw_1, score_1, bpw1, bpd1, bpl1, lbp1]}
    summary.update({team_2: [win_2, draw_2, score_2, bpw2, bpd2, bpl2, lbp2]})
    return summary

def get_expected_scores(team_1_stats, team_2_stats, team_1_df, team_2_df): #Get the expected scores for a matchup based on the previous teams' performances
    expected_scores = {}
    for stat in team_1_stats:
        expected_scores.update({'T': geo_average([team_1_stats['TF'] + geo_average(team_2_df['TA'], weights = team_2_df['Weight']),
                                           team_2_stats['TA'] + geo_average(team_1_df['TF'], weights = team_1_df['Weight'])])})
        expected_scores.update({'P': geo_average([team_1_stats['PF'] + geo_average(team_2_df['PA'], weights = team_2_df['Weight']),
                                           team_2_stats['PA'] + geo_average(team_1_df['PF'], weights = team_1_df['Weight'])])})
        expected_scores.update({'DG': geo_average([team_1_stats['DGF'] + geo_average(team_2_df['DGA'], weights = team_2_df['Weight']),
                                            team_2_stats['DGA'] + geo_average(team_1_df['DGF'], weights = team_1_df['Weight'])])})
        #print geo_average([team_1_stats['PAT1%F'] + team_2_df['PAT1AS'].astype('float').sum() / team_2_df['PAT1AA'].sum(),
        #       team_2_stats['PAT1%A'] + team_1_df['PAT1FS'].astype('float').sum() / team_1_df['PAT1FA'].sum()])
        conprob = geo_average([team_1_stats['CON%F'] + (team_2_df['CA']*team_2_df['Weight']).sum() / (team_2_d