import json
from matplotlib import pyplot as plt
from island.match import Match
from island.matches import Matches
import numpy as np
from scipy.stats import pearsonr

class Solution:
    def __init__(self, mode):
        self.mode = mode
        self.matches = Matches.from_profile_expr(lambda r: mode in r)
        self.survivals = {}
        with open('survivals.json', 'r') as f:
            self.survivals = json.load(f)
        self.neighbors = {}
        self.read_neighbor()
        self.suff = 0
        self.insuff = 0
        self.detail_suff = [0]*2
        self.detail_insuff = [0]*2

    def read_neighbor(self):
        for i, m in enumerate(self.matches.data):
            n = {}
            for r in m.query('neighbor', 'create').raw_data:
                if r['a'] in n:
                    n[r['a']].append(r['b'])
                else:
                    n[r['a']] = [r['b']]

                if r['b'] in n:
                    n[r['b']].append(r['a'])
                else:
                    n[r['b']] = [r['a']]
            self.neighbors[self.matches.names[i]] = n

    def get_reason(self, m, i, target, ttr):
        tr = 1440
        for k in m.query('action', 'request').where(lambda x: x['rno'] == i and x['from'] == target).raw_data:
            tr -= k['tr']
        for k in m.query('action', 'cancel').where(lambda x: x['rno'] == i and x['from'] == target).raw_data:
            tr += m.query('action', 'request').where(lambda x: x['rno'] == i and x['from'] == target and x['to'] == k['to'] and x['log_id'] < k['log_id']).orderby('log_id').raw_data[-1]['tr']
        for k in m.query('action', 'deny').where(lambda x: x['rno'] == i and x['to'] == target).raw_data:
            tr += m.query('action', 'request').where(lambda x: x['rno'] == i and x['from'] == target and x['to'] == k['from'] and x['log_id'] < k['log_id']).orderby('log_id').raw_data[-1]['tr']
        for k in m.query('action', 'approve').where(lambda x: x['rno'] == i and x['from'] == target).raw_data:
            tr -= k['tr']
        return tr >= ttr


    def new_partner_reason(self):
        re_after = [0] * 2  # [c,d]
        su_after = [0] * 2
        for m in self.matches.data:
            info = m.query('game', 'created').select('info').first()['info']
            game_end_at = int(info['game_end_at'])

            for p in m.query('player', 'join').raw_data:
                pid = p['pid']
                for i in range(2, game_end_at):
                    previous_round_partner = []
                    c, t = 0, 0
                    for r in m.query('action', 'done').where(lambda x: x['rno'] == i - 1 and (x['a'] == pid or x['b'] == pid)).raw_data:
                        if r['a'] == pid:
                            previous_round_partner.append(r['b'])
                            if r['act_a'] == 'C':
                                c += 1
                        else:
                            previous_round_partner.append(r['a'])
                            if r['act_b'] == 'C':
                                c += 1
                        t += 1
                    is_coop = 0 if c * 2 >= t else 1

                    new_partner_requester = {}
                    for r in m.query('action', 'request').where(lambda x: x['rno'] == i and (x['from'] == pid or x['to'] == pid)).raw_data:
                        if r['from'] == pid:
                            if r['to'] not in previous_round_partner:
                                # new_partner_request += 1
                                new_partner_requester[r['to']] = r['tr']
                        else:
                            if r['from'] not in previous_round_partner:
                                # new_partner_request += 1
                                new_partner_requester[r['from']] = r['tr']
                    
                    if not new_partner_requester:
                        continue
                    re_after[is_coop] += len(new_partner_requester)
                    new_partner_succ = 0
                    new_partner = []
                    for r in m.query('action', 'done').where(lambda x: x['rno'] == i and (x['a'] == pid or x['b'] == pid)).raw_data:
                        if r['a'] == pid:
                            if r['b'] not in previous_round_partner:
                                new_partner_succ += 1
                                new_partner.append(r['b'])
                        else:
                            if r['a'] not in previous_round_partner:
                                new_partner_succ += 1
                                new_partner.append(r['a'])
                    su_after[is_coop] += new_partner_succ

                    for npr, ntr in new_partner_requester.items():
                        if npr not in new_partner:
                            if self.get_reason(m, i, npr, ntr):
                                self.suff += 1
                                self.detail_suff[is_coop] += 1
                            else:
                                self.insuff += 1
                                self.detail_insuff[is_coop] += 1

        for i, _ in enumerate(su_after):
            print(su_after[i], re_after[i], su_after[i] / re_after[i])
            su_after[i] /= re_after[i]
        return su_after


if __name__ == '__main__':
    print('CLASSIC')
    sc = Solution('CLASSIC')
    npc_after = sc.new_partner_reason()
    print("reason: ", sc.suff, sc.insuff, sc.insuff / (sc.suff + sc.insuff))
    print("reason(c): ", sc.detail_suff[0], sc.detail_insuff[0], sc.detail_insuff[0] / (sc.detail_suff[0] + sc.detail_insuff[0]))
    print("reason(d): ", sc.detail_suff[1], sc.detail_insuff[1], sc.detail_insuff[1] / (sc.detail_suff[1] + sc.detail_insuff[1]))
    print('SURVIVE')
    ss = Solution('SURVIVE')
    nps_after = ss.new_partner_reason()
    print("reason: ", ss.suff, ss.insuff, ss.insuff / (ss.suff + ss.insuff))
    print("reason(c): ", ss.detail_suff[0], ss.detail_insuff[0], ss.detail_insuff[0] / (ss.detail_suff[0] + ss.detail_insuff[0]))
    print("reason(d): ", ss.detail_suff[1], ss.detail_insuff[1], ss.detail_insuff[1] / (ss.detail_suff[1] + ss.detail_insuff[1]))
