#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import calendar
import os

import pandas as pd


# Правила подсчета очков:
#
# за участие в матче – 2 очка, если сыграно 10 минут и больше; 1 очко, если сыграно меньше 10 минут
#
# за победу – 3 очка (в гостях); 2 очка (дома)
#
# за поражение – минус 3 очка (дома); минуc 2 очка (в гостях)
#
# Принцип начисления очков следующий:
#
# количество очков + количество передач + количество перехватов + количество подборов +
# количество блок-шотов + количество совершенных штрафных + количество совершенных двухочковых + количество совершенных трехочковых
#
#  - количество попыток штрафных бросков - количество попыток двухочковых – количество попыток трехочковых –
# удвоенная цифра от количества потерь - количество фолов

def convert_to_sec(time_str):
    if pd.isnull(time_str):
        return 0
    try:
        m, s = time_str.split(':')
        return int(m) * 60 + int(s)
    except Exception as inst:
        print(time_str)
        print(type(inst))  # the exception instance
        print(inst.args)  # arguments stored in .args


def get_sec(row):
    time_str = row['minutes']
    return convert_to_sec(time_str)


def getOrDefault(value):
    if pd.isnull(value):
        return 0
    return int(value)


def extractYear(row):
    return row['date'].year


def extractMonth(row):
    return row['date'].month


def extractDay(row):
    return row['date'].day


def concat1(row):
    return row['opponent'] + str(row['year'])


def concat2(row):
    return row['team'] + str(row['year'])


def concat3(row):
    return row['name'] + str(row['year'])


def concat4(row):
    return row['opponent'] + str(row['month']) + str(row['year'])


def concat5(row):
    return row['team'] + str(row['month']) + str(row['year'])


def concat6(row):
    return row['name'] + str(row['month']) + str(row['year'])


def getDayOfTheWeek(row):
    day = calendar.day_name[row['date'].weekday()]
    return day[:3]


def convert_age(row):
    if pd.isnull(row['age']):
        return 0
    years, days = row['age'].split('-')
    return int(years) + 1.0 * int(days) / 365


def split_result(x):
    try:
        sp = x.split('(')
        return sp[0].strip(), sp[1][:-1]
    except Exception as inst:
        print(x)
        print(type(inst))  # the exception instance
        print(inst.args)  # arguments stored in .args


#   (FG + 0.5 * 3P) / FGA
def calc_efg(row):
    try:
        fg = row['fg']
        fg3 = row['fg3']
        fga = row['fga']
        if fga == 0:
            return 0.0
        return (fg + 0.5 * fg3) / fga
    except Exception as inst:
        print(row)
        print(type(inst))  # the exception instance
        print(inst.args)  # arguments stored in .args


def calc_fantasy(row):
    if pd.isnull(row['minutes']):
        return 0
    fantasy_points = 0
    if convert_to_sec(row['minutes']) >= 10 * 60:
        fantasy_points += 2
    else:
        fantasy_points += 1
    if 'W' in str(row['result']):
        if row['location'] == '@':
            fantasy_points += 3
        else:
            fantasy_points += 2
    else:
        if row['location'] == '@':
            fantasy_points -= 2
        else:
            fantasy_points -= 3
    fantasy_points += getOrDefault(row['pts'])
    fantasy_points += getOrDefault(row['ast'])
    fantasy_points += getOrDefault(row['stl'])
    fantasy_points += getOrDefault(row['trb'])
    fantasy_points += getOrDefault(row['blk'])
    fantasy_points += getOrDefault(row['ft'])
    fantasy_points += getOrDefault(row['fg'])

    fantasy_points -= getOrDefault(row['fta'])
    fantasy_points -= getOrDefault(row['fga'])
    fantasy_points -= 2 * getOrDefault(row['tov'])
    fantasy_points -= getOrDefault(row['pf'])

    return fantasy_points


def enrich_player_df(df):
    df['fantasy_points'] = df.apply(lambda row: calc_fantasy(row), axis=1)
    df['year'] = df.apply(lambda row: extractYear(row), axis=1)
    df['month'] = df.apply(lambda row: extractMonth(row), axis=1)
    df['day'] = df.apply(lambda row: extractDay(row), axis=1)
    df['opponent2'] = df.apply(lambda row: concat1(row), axis=1)
    df['opponent3'] = df.apply(lambda row: concat4(row), axis=1)
    df['team3'] = df.apply(lambda row: concat5(row), axis=1)
    df['name3'] = df.apply(lambda row: concat6(row), axis=1)
    df['name2'] = df.apply(lambda row: concat3(row), axis=1)
    df['team2'] = df.apply(lambda row: concat2(row), axis=1)
    df['age1'] = df.apply(lambda row: convert_age(row), axis=1)
    df['seconds'] = df.apply(lambda row: get_sec(row), axis=1)

    for i in range(1, 6):
        df['mean_pts_' + str(i)] = df['pts'].rolling(i).mean().shift(1)

    df['efg'] = df.apply(lambda row: calc_efg(row), axis=1)
    df['mefg'] = df['efg'].expanding().mean().shift(1)
    df['day_of_the_week'] = df.apply(lambda row: getDayOfTheWeek(row), axis=1)
    df['mfp'] = df['fantasy_points'].expanding().mean().shift(1)
    df['medfp'] = df['fantasy_points'].expanding().median().shift(1)
    df['msec'] = df['seconds'].expanding().mean().shift(1)
    df['mpts'] = df['pts'].expanding().mean().shift(1)
    df['mast'] = df['ast'].expanding().mean().shift(1)
    df['mtrb'] = df['trb'].expanding().mean().shift(1)
    df['mstl'] = df['stl'].expanding().mean().shift(1)
    df['mpf'] = df['pf'].expanding().mean().shift(1)
    df['mtov'] = df['tov'].expanding().mean().shift(1)
    df['mblk'] = df['blk'].expanding().mean().shift(1)
    df['mfg'] = df['fg'].expanding().mean().shift(1)
    df['mfg3'] = df['fg3'].expanding().mean().shift(1)
    df['mft'] = df['ft'].expanding().mean().shift(1)

    df['mfg3_pct'] = df['fg3_pct'].expanding().mean().shift(1)
    df['mfg_pct'] = df['fg_pct'].expanding().mean().shift(1)
    df['mft_pct'] = df['ft_pct'].expanding().mean().shift(1)

    # number of games in last 5 days
    df['rest_days'] = df['date'].diff().apply(lambda x: x.days)

    for i in [1, 7, 10, 11, 12]:
        df['mean_rest_days_' + str(i)] = df['rest_days'].rolling(i).mean().shift(1)

    for i in [10, 21, 31, 38, 39]:
        df['mean_fantasy_' + str(i)] = df['fantasy_points'].rolling(i).mean().shift(1)

    for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
        df['mean_sec_' + str(i)] = df['seconds'].rolling(i).mean().shift(1)

    for i in [3, 4, 12, 16, 17, 28, 36]:
        df['skew_fantasy_' + str(i)] = df['fantasy_points'].rolling(i).skew().shift(1)

    return df


def enrich_player_df_for_upcoming_games(df):
    df['fantasy_points'] = df.apply(lambda row: calc_fantasy(row), axis=1)
    df['year'] = df.apply(lambda row: extractYear(row), axis=1)
    df['month'] = df.apply(lambda row: extractMonth(row), axis=1)
    df['day'] = df.apply(lambda row: extractDay(row), axis=1)
    df['opponent2'] = df.apply(lambda row: concat1(row), axis=1)
    df['opponent3'] = df.apply(lambda row: concat4(row), axis=1)
    df['team3'] = df.apply(lambda row: concat5(row), axis=1)
    df['name3'] = df.apply(lambda row: concat6(row), axis=1)
    df['name2'] = df.apply(lambda row: concat3(row), axis=1)
    df['team2'] = df.apply(lambda row: concat2(row), axis=1)
    df['age1'] = df.apply(lambda row: convert_age(row), axis=1)
    df['seconds'] = df.apply(lambda row: get_sec(row), axis=1)

    for i in range(1, 6):
        df['mean_pts_' + str(i)] = df['pts'].rolling(i).mean().shift(1)

    df['efg'] = df.apply(lambda row: calc_efg(row), axis=1)
    df['mefg'] = df['efg'].expanding().mean().shift(1)
    df['day_of_the_week'] = df.apply(lambda row: getDayOfTheWeek(row), axis=1)
    df['mfp'] = df['fantasy_points'].expanding().mean().shift(1)
    df['medfp'] = df['fantasy_points'].expanding().median().shift(1)
    df['msec'] = df['seconds'].expanding().mean().shift(1)
    df['mpts'] = df['pts'].expanding().mean().shift(1)
    df['mast'] = df['ast'].expanding().mean().shift(1)
    df['mtrb'] = df['trb'].expanding().mean().shift(1)
    df['mstl'] = df['stl'].expanding().mean().shift(1)
    df['mpf'] = df['pf'].expanding().mean().shift(1)
    df['mtov'] = df['tov'].expanding().mean().shift(1)
    df['mblk'] = df['blk'].expanding().mean().shift(1)
    df['mfg'] = df['fg'].expanding().mean().shift(1)
    df['mfg3'] = df['fg3'].expanding().mean().shift(1)
    df['mft'] = df['ft'].expanding().mean().shift(1)

    df['mfg3_pct'] = df['fg3_pct'].expanding().mean().shift(1)
    df['mfg_pct'] = df['fg_pct'].expanding().mean().shift(1)
    df['mft_pct'] = df['ft_pct'].expanding().mean().shift(1)

    # number of games in last 5 days
    df['rest_days'] = df['date'].diff().apply(lambda x: x.days)

    for i in [1, 7, 10, 11, 12]:
        df['mean_rest_days_' + str(i)] = df['rest_days'].rolling(i).mean().shift(1)

    for i in [10, 21, 31, 38, 39]:
        df['mean_fantasy_' + str(i)] = df['fantasy_points'].rolling(i).mean().shift(1)

    for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
        df['mean_sec_' + str(i)] = df['seconds'].rolling(i).mean().shift(1)

    for i in [3, 4, 12, 16, 17, 28, 36]:
        df['skew_fantasy_' + str(i)] = df['fantasy_points'].rolling(i).skew().shift(1)
    return df


dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d')


def enrich_all_data():
    for root, dirs, files in os.walk("nba"):
        for file in files:
            if file.endswith(".csv"):
                try:
                    path = os.path.join(root, file)
                    if path.find('fantasy') == -1 and path.find('2018.csv') != -1:
                        f = open(path)
                        print(path)
                        lines = f.readlines()
                        if len(lines) > 1:
                            df = pd.read_csv(path,
                                             parse_dates=['date'],
                                             date_parser=dateparse)
                        if not df.empty:
                            df.fillna(df.mean(), inplace=True)
                            df = enrich_player_df(df)
                            join = os.path.join(root, "fantasy")
                            if not os.path.exists(join):
                                os.mkdir(join)
                            df.to_csv(os.path.join(root, "fantasy", file), index=False)
                except Exception as inst:
                    print(file)
                    print(df.head())
                    print(type(inst))  # the exception instance
                    print(inst.args)  # arguments stored in .args
