"""
LLM Evaluator - batch evaluation of LLM performance on Sudoku.
"""

from __future__ import annotations

import time
from typing import List, Dict, Optional
from datetime import datetime

from ..core import LLMConfig, EvaluationResult, PlayResult, PlayMode, SudokuGame
from ..sudoku.generator import SudokuGenerator
from .player import LLMPlayer


class LLMEvaluator:
    """Evaluates LLM performance on multiple Sudoku games."""

    DEFAULT_DIFFICULTIES = ["easy", "medium", "hard"]
    DEFAULT_GAMES_PER_DIFFICULTY = 3

    def __init__(self, config: LLMConfig):
        self.config = config
        self.player = LLMPlayer(config)

    def evaluate(
        self,
        difficulties: List[str] = None,
        games_per_difficulty: int = None,
        mode: PlayMode = PlayMode.STEP_BY_STEP,
        max_moves: int = 200,
    ) -> EvaluationResult:
        difficulties = difficulties or self.DEFAULT_DIFFICULTIES
        games_per_difficulty = games_per_difficulty or self.DEFAULT_GAMES_PER_DIFFICULTY

        all_results: List[PlayResult] = []
        results_by_difficulty: Dict[str, Dict] = {}

        start_time = time.time()

        for difficulty in difficulties:
            difficulty_results: List[PlayResult] = []
            correct = 0
            completed = 0

            for i in range(games_per_difficulty):
                game_data = SudokuGenerator.generate_game(difficulty)
                game = SudokuGame(
                    id=f"{difficulty}_{i+1}",
                    puzzle=game_data["puzzle"],
                    solution=game_data["solution"],
                    difficulty=difficulty,
                    clues=game_data["clues"],
                )

                try:
                    result = self.player.play(game, mode, max_moves)
                    difficulty_results.append(result)
                    all_results.append(result)

                    if result.completed:
                        completed += 1
                    if result.correct:
                        correct += 1

                except Exception as e:
                    continue

            results_by_difficulty[difficulty] = {
                "total": games_per_difficulty,
                "completed": completed,
                "correct": correct,
                "accuracy": correct / games_per_difficulty if games_per_difficulty > 0 else 0,
            }

        total_time = time.time() - start_time
        total_games = len(all_results)
        completed_games = sum(1 for r in all_results if r.completed)
        correct_games = sum(1 for r in all_results if r.correct)

        return EvaluationResult(
            model_name=self.config.model,
            provider=self.config.provider,
            total_games=total_games,
            completed_games=completed_games,
            correct_games=correct_games,
            overall_accuracy=correct_games / total_games if total_games > 0 else 0,
            total_time=total_time,
            results_by_difficulty=results_by_difficulty,
            play_results=all_results,
            evaluated_at=datetime.now(),
        )


def evaluate_model(
    config: LLMConfig,
    difficulties: List[str] = None,
    games_per_difficulty: int = None,
    mode: PlayMode = PlayMode.STEP_BY_STEP,
) -> EvaluationResult:
    evaluator = LLMEvaluator(config)
    return evaluator.evaluate(difficulties, games_per_difficulty, mode)