"""Evaluacny harness: odohra N kol medzi 4 hracmi a spocita metriky.

Metriky per hrac (viz rl/DESIGN.md, sekcia 5): priemerne body na kolo
a presnost tipu (% kol s presne trafenym tipom). Sedadla sa medzi kolami
rotuju, aby ziadny hrac nebol systematicky zvyhodneny poradim tipovania.

Spustenie ako skript porovna baseline botov:
    py -m rl.evaluate --rounds 500 --seed 7
"""

import argparse
from random import Random

from bridzik import ROUNDS_PER_SERIES
from rl.env import PHASE_GUESS, RoundEnv


def play_round(players: list, env: RoundEnv, round_number: int = None,
               first_player: int = None) -> list:
    """Odohra jedno kolo; `players[seat]` rozhoduje za sedadlo `seat`.

    Vrati body 4 sedadiel (`Round.get_points_summary()`).
    """
    decision = env.reset(round_number, first_player)
    while True:
        seat = decision.player
        if decision.phase == PHASE_GUESS:
            action = players[seat].guess(env.round, seat)
        else:
            action = players[seat].play(env.round, seat)
        decision, rewards, done = env.step(action)
        if done:
            return rewards


def evaluate(players: list, n_rounds: int, rng: Random = None,
             round_numbers: list = None) -> list:
    """Odohra `n_rounds` kol s rotaciou sedadiel; vrati stats per hrac.

    Vystup: zoznam dictov v poradi `players` --
    {'avg_points': float, 'hit_rate': float, 'rounds': int}.
    """
    rng = rng if rng is not None else Random()
    env = RoundEnv(rng)
    points = [0] * 4
    hits = [0] * 4
    for i in range(n_rounds):
        round_number = rng.choice(round_numbers) if round_numbers \
            else rng.randrange(ROUNDS_PER_SERIES)
        # rotacia: sedadlo s obsadzuje players[(s + i) % 4]
        seating = [players[(s + i) % 4] for s in range(4)]
        rewards = play_round(seating, env, round_number)
        for seat in range(4):
            player_index = (seat + i) % 4
            points[player_index] += rewards[seat]
            hits[player_index] += rewards[seat] > 0
    return [{'avg_points': points[p] / n_rounds,
             'hit_rate': hits[p] / n_rounds,
             'rounds': n_rounds} for p in range(len(players))]


def main():
    from rl.players import HeuristicPlayer, RandomPlayer

    parser = argparse.ArgumentParser(description='Evaluacia baseline botov')
    parser.add_argument('--rounds', type=int, default=500)
    parser.add_argument('--seed', type=int, default=7)
    parser.add_argument('--mc-samples', type=int, default=100)
    args = parser.parse_args()

    rng = Random(args.seed)
    lineups = [
        ('4x random', [RandomPlayer(rng) for _ in range(4)]),
        ('1x heuristika + 3x random',
         [HeuristicPlayer(rng, n_samples=args.mc_samples)]
         + [RandomPlayer(rng) for _ in range(3)]),
        ('4x heuristika',
         [HeuristicPlayer(rng, n_samples=args.mc_samples) for _ in range(4)]),
    ]
    for label, players in lineups:
        stats = evaluate(players, args.rounds, rng)
        print(f'\n{label} ({args.rounds} kol):')
        for i, s in enumerate(stats):
            print(f'  hrac {i}: {s["avg_points"]:6.2f} bodov/kolo, '
                  f'tip trafeny {100 * s["hit_rate"]:5.1f} %')


if __name__ == '__main__':
    main()
