from game import StopWatch, ScoreDiffMancalaNode, MancalaNode, GameNode, current_ms_time
import os

# This is code for a simple round-robin FairKalah tournament with random, fair FairKalah boards for each game.

num_games = 9  # TODO: Set the number of games for each match-up, preferably odd.
ms_per_game = 300000  # TODO: Set the maximum number of milliseconds per game.  Each player gets half as a limit.


def run_games(player1_id, player2_id, file):
    player1_class_name = f'{player1_id}MancalaPlayer'
    mod = __import__(player1_id, fromlist=[player1_class_name])
    player1_class = getattr(mod, player1_class_name)
    player1 = player1_class()
    player2_class_name = f'{player2_id}MancalaPlayer'
    mod = __import__(player2_id, fromlist=[player2_class_name])
    player2_class = getattr(mod, player2_class_name)
    player2 = player2_class()
    players = [player1, player2]
    score_stats = 4 * [0]  # Player 1 games won, player 2 games won, player 1 points scored, player 2 points scores
    times = 2 * [0]

    for g in range(num_games):
        print('Game', g + 1, 'started')
        ran_out_clock = False
        player_ms_remaining = [ms_per_game // 2, ms_per_game // 2]

        # Create a clock
        clock = StopWatch()

        # Create a node with a random FairKalah board initial state
        node = ScoreDiffMancalaNode(0)
        file.write(str(node) + '\n')

        # While game is on...
        winner = 'DRAW'
        while not node.is_game_over():
            current_player = node.player
            is_max_player = current_player == GameNode.MAX

            # Request move from current player
            clock.reset()
            clock.start()
            move = players[current_player].choose_move(MancalaNode(other=node), player_ms_remaining[current_player])
            time_taken = clock.stop()

            # Deduct time taken
            player_ms_remaining[current_player] -= time_taken
            if player_ms_remaining[current_player] < 0:
                ran_out_clock = True
                if is_max_player:
                    file.write('Player 1 game timer expired.\n')
                    score_stats[3] += 48
                    winner = 'PLAYER 2 WINS'
                else:
                    file.write('Player 2 game timer expired.\n')
                    score_stats[2] += 48
                    winner = 'PLAYER 1 WINS'
                break

            try:
                file.write(f'Player {"1" if is_max_player else "2"} makes move {MancalaNode.move_to_string(move)}.\n')
                child = node.child_copy()
                child.make_move(move)
                node = child
                file.write(str(node) + '\n')
            except ValueError:
                file.write('ERROR: Player', '1' if is_max_player else '2',
                           'makes an ILLEGAL MOVE and forfeits all points.')
                winner = 'PLAYER 2 WINS' if is_max_player else 'PLAYER 1 WINS'
                break

        # Display winner and statistics
        if node.is_game_over():
            if node.utility() > 0:
                winner = 'PLAYER 1 WINS'
            elif node.utility() < 0:
                winner = 'PLAYER 2 WINS'
            else:
                winner = 'DRAW'

        file.write('Time Taken (ms):\n')
        t = int(ms_per_game/2 - player_ms_remaining[GameNode.MAX])
        times[0] += t
        file.write(f'Player 1: {t}\n')
        t = int(ms_per_game/2 - player_ms_remaining[GameNode.MIN])
        times[1] += t
        file.write(f'Player 2: {t}\n')
        file.write(winner + '\n')
        if winner == 'PLAYER 1 WINS':
            score_stats[0] += 1
        elif winner == 'PLAYER 2 WINS':
            score_stats[1] += 1
        if not ran_out_clock:
            score_stats[2] += node.state[MancalaNode.MAX_SCORE_PIT]
            score_stats[3] += node.state[MancalaNode.MIN_SCORE_PIT]
    file.write('-----------------------------------------------------------------------------------\n')
    file.write(f'Player 1 wins: {score_stats[0]}\n')
    file.write(f'Player 2 wins: {score_stats[1]}\n')
    file.write(f'Player 1 points won: {score_stats[2]}\n')
    file.write(f'Player 2 points won: {score_stats[3]}\n')
    file.write(f'Player 1 total time used: {times[0]}\n')
    file.write(f'Player 2 total time used: {times[1]}\n')
    file.write(f'Player 1 name: {player1_id}\n')
    file.write(f'Player 2 name: {player2_id}\n')
    return score_stats


if __name__ == "__main__":
    startTime = current_ms_time()
    # TODO - Create a list of unique ID strings. If the unique ID is 'X', then it there should be a file 'X.py'
    #  containing the class definition for 'XMancalaPlayer', etc., as shown in the template file UniqueID.py.
    player_ids = ['FixedDepthDemo', 'FixedDepthDemo']
    competitors = [s + 'MancalaPlayer' for s in player_ids]
    log_folder_name = 'log'
    if not os.path.exists(log_folder_name):
        os.mkdir('log_folder_name')
    filename = 'MancalaTournamentResults.csv'
    results = open(filename, 'w')
    num_players = len(player_ids)
    match_wins = num_players * [0]
    game_wins = num_players * [0]
    points = num_players * [0]
    results.write('"TOURNAMENT RESULTS:"\n')
    results.write('"First Player (Win:Loss) Ratios:"\n')
    results.write(',"Second Player"\n')
    results.write('"First Player"')
    for i in range(num_players):
        results.write(f',\"{i}-{player_ids[i]}\"')
    results.write('\n')
    for i in range(num_players):
        results.write(f'\"{i}-{player_ids[i]}\"')
        for j in range(num_players):
            results.write(',')
            if i == j:
                continue
            # individual matches recorded in detail in logs directory for later inspection
            log_filename = os.path.join(log_folder_name, f'tournament.{i}.{j}.log')
            log_file = open(log_filename, 'w')
            # Console high-level progress
            print(f'Playing games with players MAX:{player_ids[i]}, MIN:{player_ids[j]}:')
            scores = run_games(player_ids[i], player_ids[j], log_file)
            log_file.flush()
            log_file.close()
            if scores[0] > scores[1]:
                match_wins[i] += 1
            elif scores[1] > scores[0]:
                match_wins[j] += 1
            game_wins[i] += scores[0]
            game_wins[j] += scores[1]
            points[i] += scores[2]
            points[j] += scores[3]
            results.write(f'\"({scores[0]}:{scores[1]})\"')
        results.write('\n')
    results.write('\n\n')
    results.write('"SUMMARY STATISTICS"\n')
    results.write('"The winner of this table is determined by most winning matches."\n')
    results.write('"Ties are broken according to total game wins."\n')
    results.write('"Further ties are broken according to total points across all games."\n')
    results.write(',"Match Wins","Total Game Wins","Total Points"\n')
    for i in range(num_players):
        results.write(f'\"{i}-{player_ids[i]}\",{match_wins[i]},{game_wins[i]},{points[i]}\n')
    results.flush()
    results.close()

    print(f'Time taken to calculate results: {current_ms_time() - startTime}ms\n')
