# template : https://docs.google.com/spreadsheets/d/1KPt_KE_Z_RcJh6Wz-VCuU14HEQusKxBeCUzO99SpE2c/edit?usp=sharing
import datetime
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from threading import Thread
import json
import os
import time
from SWParser import *
import SWPlugin
from itertools import groupby
from string import ascii_uppercase

result_map = {
    1: 'win',
    2: 'lost',
    3: 'draw'
}

summary_battle_columns = {
    1 : ('B', 'G'),
    2 : ('H', 'M'),
    3 : ('N', 'S'),
    4 : ('T', 'Y'),
    5 : ('Z', 'AE'),
    6 : ('AF', 'AK'),
    7 : ('AL', 'AQ'),
    8 : ('AR', 'AW'),
    9 : ('AX', 'BC'),
    10 : ('BD', 'BI'),
    11 : ('BJ', 'BO'),
    12 : ('BP', 'BU'),
}

column_names = []
for p in range(5):
    for c in ascii_uppercase:
        prefix = ascii_uppercase[p - 1] if p > 0 else ''
        column_names.append(prefix + c)

attack_tab = 'Attack'
attack_summary = 'Attack Summary'
log_tab = 'Log'
defense_tab = 'Defense Summary'
sheet_name = 'Guildwar %s'

def get_match_id(data):
    return data['match_id']

class GWLogger(SWPlugin.SWPlugin):
    def __init__(self):
        if not os.path.exists('swproxy.config'):
            self.config = {}
            return

        with open('swproxy.config') as f:
            self.config = json.load(f)

    def group_battles(self, cache):
        list = sorted(cache.values(), key=get_match_id)
        grouped = groupby(list, lambda x: x['match_id'])
        groups = []
        for key, group in grouped:
            matches = []
            battle = {}
            first = True
            for item in group:
                if first:
                    first = False
                    battle['guild'] = item['op_guild']
                    battle['type'] = item['type']
                    battle['match_id'] = item['match_id']
                matches.append(item)
            battle['matches'] = matches
            groups.append(battle)
        return groups

    def get_worksheet(self, key, sheet):
        date = datetime.date.today()
        days_until_saturday = 5 - date.weekday()
        next_saturday = date + datetime.timedelta(days_until_saturday)

        scope = ['https://spreadsheets.google.com/feeds']
        credentials = ServiceAccountCredentials.from_json_keyfile_name(key, scope)
        gc = gspread.authorize(credentials)
        sheet_name = 'Guildwar %s' % next_saturday.strftime('%m-%d-%Y')
        return gc.open(sheet_name)

    def gp_values(self, atk1, atk2, gp):
        # 2 wins
        if atk1 == 'win' and atk2 == 'win':
            return gp / 2, gp/2

        # 2 loses
        if gp == 0:
            return 0, 0

        # draw
        if atk1 == 'draw':
            return 1, gp - 1
        if atk2 == 'draw':
            return gp-1, 1

        if atk1 == 'win':
            return gp, 0
        else:
            return 0, gp

    def write_attack_tab(self, sheet, data, members_list, opponent_list, battle_index):
        wks = sheet.worksheet(attack_tab)
        line = (battle_index * 33) + 1
        cells = wks.range('A%s:AY%s' % (line, line + 32))

        for i, cell in enumerate(cells):
            if i > 101:
                cell.value = ''

        cells[1].value = data['guild']
        for i, name in enumerate(members_list):
            cells[(i * 51) + 102].value = name

        for match in data['matches']:
            index_member = members_list.index(match['member_name'])
            index_opponent = opponent_list.index(match['op_name'])
            cell = (index_member *51) + 103 + index_opponent * 2
            round1, round2 = self.gp_values(match['result_1'], match['result_2'], match['gp'])
            cells[cell].value = round1
            cells[cell + 1].value = round2

        wks.update_cells(cells)

    def write_attack_summary_members(self, sheet, members_list):
        wks = sheet.worksheet(attack_summary)

        cells = wks.range('A4:A33')
        for i, name in enumerate(members_list):
            cells[i].value = name
        wks.update_cells(cells)

    def write_attack_summary(self, sheet, data, members_list, opponent_list, battle_index):
        wks = sheet.worksheet(attack_summary)
        start_col, end_col = summary_battle_columns[battle_index +1]

        cells = wks.range('%s2:%s33' % (start_col, end_col))

        # clean everything
        for i, cell in enumerate(cells):
            if i > 12 and i % 32 > 1:
                cell.value = ''

        # guild name
        cells[0].value = data['guild']

        sword_counter = {}
        for match in data['matches']:
            member = match['member_name']

            if member not in sword_counter:
                sword_counter[member] = 0

            swords = sword_counter[member]
            sword_counter[member] += 1

            index_member = members_list.index(member)
            cell = (6*index_member) + (swords * 2) + 12
            round1, round2 = self.gp_values(match['result_1'], match['result_2'], match['gp'])
            cells[cell].value = round1
            cells[cell + 1].value = round2

        wks.update_cells(cells)

    def get_opponent_list(self, battle_data):
        members = {}
        for entry in battle_data:
            member = entry['op_name']
            if member not in members:
                members[member] = 0
            gp = entry['gp']
            if gp > members[member]:
                members[member] = gp
        member_list = []
        for member in members:
            member_list.append({'id': member, 'gp': members[member]})
        s = sorted(member_list, key=lambda item: item['gp'], reverse=True)
        members = []
        for item in s:
            members.append(item['id'])
        return members

    def create_members_list(self, cache):
        members = {}
        for entry in cache:
            member = cache[entry]['member_name']
            if member not in members:
                members[member] = 0
            members[member] += cache[entry]['gp']
        member_list = []
        for member in members:
            member_list.append({'id': member, 'gp': members[member]})
        s = sorted(member_list, key=lambda item: item['gp'], reverse=True)
        members = []
        for item in s:
            members.append(item['id'])
        return members

    def process_request(self, req_json, resp_json):
        config = self.config
        if 'log_guildwar' not in config or not config['log_guildwar'] or 'enable_google_sheet_writer' not in config\
                or not config['enable_google_sheet_writer']:
            return

        command = req_json['command']
        if command == 'GetGuildWarBattleLogByGuildId':
            thread = Thread(target = self.log_guildwar, args = (req_json, resp_json, config))
            thread.start()

    def read_log(self, filename):
        with open(filename, 'rb') as f:
            return json.load(f)

    def process_input_json(self, resp_json):
        # read previous data
        week = datetime.date.today().strftime("%U")
        cache_name = "guildwar-%s.json" % week
        is_new_file = not os.path.exists(cache_name)
        cache = {} if is_new_file else self.read_log(cache_name)

        log_type = 'attack' if resp_json['log_type'] == 1 else 'defense'
        for guild in resp_json['battle_log_list_group']:
            for battle in guild['battle_log_list']:
                id = str(battle['rid'])

                if id in cache:
                    continue

                log_entry = {'id': id, 'type': log_type, 'member_name': battle['wizard_name'],
                             'op_name': battle['opp_wizard_name'], 'op_guild': battle['opp_guild_name'],
                             'match_id' : battle['match_id'],
                             'result_1': result_map[battle['result'][0]],
                             'result_2': result_map[battle['result'][1]],
                             'gp': battle['guild_point_var'],
                             'end': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(battle['battle_end']))}

                cache[id] = log_entry
        return cache

    def save_cache(self, cache):
        date = datetime.date.today()
        days_until_saturday = 5 - date.weekday()
        next_saturday = date + datetime.timedelta(days_until_saturday)


        week = next_saturday.strftime("%U")
        cache_name = "guildwar-%s.json" % week
        with open(cache_name, 'wb') as f:
            json.dump(cache, f)

    def get_sheet_name(self, battle_type):
        week = datetime.date.today().strftime("%U")
        type = 'Attack' if battle_type == 'attack' else 'Defense'
        return 'GW - %s (%s)' % (type, week)

    def write_log(self, battle_list, sheet):
        count = 2
        wks = sheet.worksheet(log_tab)
        for battle in battle_list:
            c = len(battle['matches'])
            cells = wks.range('A%s:I%s' % (count, count+c))
            pos = 0
            for match in battle['matches']:
                cells[pos].value = match['id']
                cells[pos+1].value = match['type']
                cells[pos+2].value = match['member_name']
                cells[pos+3].value = match['op_name']
                cells[pos+4].value = match['op_guild']
                cells[pos+5].value = match['result_1']
                cells[pos+6].value = match['result_2']
                cells[pos+7].value = match['gp']
                cells[pos+8].value = match['end']
                pos += 9
            wks.update_cells(cells)
            count += c

    def write_defense_summary(self, battle_list, member_list, sheet):
        wks = sheet.worksheet(defense_tab)

        counters = {}
        guilds = []
        guild_info = []

        # write members names
        cells = wks.range('B1:CK1')
        for i, member in enumerate(member_list):
            cells[i*3].value = member
            counters[member] = 0
        wks.update_cells(cells)

        # write defense data
        cells = wks.range('B5:CM59')

        for battle in battle_list:
            if battle['type'] == 'attack':
                continue

            guilds.append(battle['guild'])
            guild_info.append({"name": battle['guild'], "date": battle['matches'][0]['end']})

            for match in battle['matches']:
                member = match['member_name']
                count = counters[member]
                cell = (90 * count) + (member_list.index(member) * 3)
                if cell >= len(cells):
                    print member
                cells[cell].value = '#%s' % str(len(guilds))
                cells[cell + 1].value = match['result_1'].upper()[0]
                cells[cell + 2].value = match['result_2'].upper()[0]
                counters[member] += 1
        wks.update_cells(cells)

    def log_guildwar(self, req_json, resp_json, config):
        cache = self.process_input_json(resp_json)
        self.save_cache(cache)

        member_list = self.create_members_list(cache)
        battle_list = self.group_battles(cache)

        sheet = self.get_worksheet(self.config['google_key'], self.config['sheet_name'])
        self.write_attack_summary_members(sheet, member_list)
        self.write_log(battle_list, sheet)
        self.write_defense_summary(battle_list, member_list, sheet)

        index = {'attack': 0, 'defense': 0}
        for battle in battle_list:
            op_members = self.get_opponent_list(battle['matches'])
            type = battle['type']
            battle_index = index[type]
            index[type] += 1
            if type == 'attack':
                self.write_attack_tab(sheet, battle, member_list, op_members, battle_index)
                print 'Log Attack tab'
                self.write_attack_summary( sheet, battle, member_list, op_members, battle_index)
                print 'Log Attack Summary'