"""
Module de gestion des statistiques du jeu MasterMind.
Collecte, analyse et persiste les données de jeu.
"""

import json
import os
from datetime import datetime
from typing import List, Dict, Tuple, Optional
from dataclasses import dataclass, asdict
from pathlib import Path


@dataclass
class GameRecord:
    """Enregistrement d'une partie jouée"""
    timestamp: str
    won: bool
    attempts: int
    secret: Optional[List[int]] = None  # Code secret (optionnel pour vie privée)

    def to_dict(self) -> Dict:
        """Convertit l'enregistrement en dictionnaire pour JSON"""
        return asdict(self)

    @classmethod
    def from_dict(cls, data: Dict) -> 'GameRecord':
        """Crée un enregistrement depuis un dictionnaire JSON"""
        return cls(**data)


class StatisticsManager:
    """Gestionnaire des statistiques du jeu"""

    def __init__(self, stats_file: str = "data/statistics.json"):
        """
        Initialise le gestionnaire et charge les statistiques existantes.

        Args:
            stats_file: Chemin vers le fichier de statistiques JSON
        """
        self.stats_file = Path(stats_file)
        self.games: List[GameRecord] = []
        self._load()

    def _load(self) -> None:
        """Charge les statistiques depuis le fichier JSON"""
        if self.stats_file.exists():
            try:
                with open(self.stats_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    self.games = [GameRecord.from_dict(record) for record in data.get('games', [])]
            except (json.JSONDecodeError, KeyError) as e:
                print(f"⚠️  Erreur chargement statistiques: {e}. Initialisation vide.")
                self.games = []
        else:
            # Créer le dossier data si nécessaire
            self.stats_file.parent.mkdir(parents=True, exist_ok=True)
            self.games = []

    def save(self) -> None:
        """Sauvegarde les statistiques dans le fichier JSON"""
        data = {
            "total_games": len(self.games),
            "games_won": sum(1 for g in self.games if g.won),
            "last_updated": datetime.now().isoformat(),
            "games": [game.to_dict() for game in self.games]
        }
        with open(self.stats_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)

    def record_game(self, won: bool, attempts: int, secret: Optional[List[int]] = None) -> None:
        """
        Enregistre une partie terminée.

        Args:
            won: True si le joueur a gagné
            attempts: Nombre de tentatives utilisées
            secret: Code secret (optionnel, pour分析)
        """
        record = GameRecord(
            timestamp=datetime.now().isoformat(),
            won=won,
            attempts=attempts,
            secret=secret
        )
        self.games.append(record)
        self.save()

    def get_summary(self) -> Dict[str, any]:
        """
        Retourne un résumé des statistiques globales.

        Returns:
            Dictionnaire avec métriques clés
        """
        total = len(self.games)
        if total == 0:
            return {
                "total_games": 0,
                "games_won": 0,
                "win_rate": 0.0,
                "avg_attempts": 0.0,
                "best_victory": None,
                "recent_win_rate": 0.0
            }

        won_games = [g for g in self.games if g.won]
        total_won = len(won_games)

        # Taux de victoire global
        win_rate = total_won / total

        # Tentatives moyennes (victoires seulement)
        avg_attempts = sum(g.attempts for g in won_games) / total_won if total_won > 0 else 0

        # Meilleure victoire (moins de tentatives)
        best_victory = min(g.attempts for g in won_games) if won_games else None

        # Win rate sur les 10 dernières parties (ou moins si moins de parties)
        recent_games = self.games[-10:] if len(self.games) >= 10 else self.games
        recent_won = sum(1 for g in recent_games if g.won)
        recent_win_rate = recent_won / len(recent_games)

        return {
            "total_games": total,
            "games_won": total_won,
            "win_rate": round(win_rate * 100, 1),
            "avg_attempts": round(avg_attempts, 1),
            "best_victory": best_victory,
            "recent_win_rate": round(recent_win_rate * 100, 1),
            "recent_games_count": len(recent_games)
        }

    def get_attempt_distribution(self) -> Dict[int, int]:
        """
        Retourne la distribution des tentatives pour les victoires.

        Returns:
            Dictionnaire {tentatives: nombre} pour tentatives 1-15
        """
        won_games = [g for g in self.games if g.won]
        distribution = {}
        for attempts in range(1, 16):  # 1 à 15 tentatives max
            count = sum(1 for g in won_games if g.attempts == attempts)
            if count > 0:
                distribution[attempts] = count
        return distribution

    def get_recent_games(self, n: int = 10) -> List[Dict]:
        """
        Retourne les n dernières parties.

        Args:
            n: Nombre de parties à retourner

        Returns:
            Liste de dictionnaires avec données des parties
        """
        recent = self.games[-n:] if n > 0 else []
        return [
            {
                "timestamp": g.timestamp,
                "won": g.won,
                "attempts": g.attempts,
                "date": datetime.fromisoformat(g.timestamp).strftime("%d/%m/%Y %H:%M")
            }
            for g in recent
        ]

    def clear_stats(self) -> None:
        """Réinitialise toutes les statistiques (avec confirmation)"""
        self.games = []
        self.save()

    def get_streak(self) -> Tuple[int, str]:
        """
        Calcule la série actuelle (victoires/défaites consécutives).

        Returns:
            Tuple (longueur, type) où type est "victoire" ou "défaite"
        """
        if not self.games:
            return (0, "aucune")

        current_streak = 1
        current_type = "victoire" if self.games[-1].won else "défaite"

        for game in reversed(self.games[:-1]):
            if (current_type == "victoire" and game.won) or (current_type == "défaite" and not game.won):
                current_streak += 1
            else:
                break

        return (current_streak, current_type)


def format_stat_summary(summary: Dict) -> str:
    """Formate le résumé statistique en texte lisible"""
    if summary["total_games"] == 0:
        return "📊 Aucune partie enregistrée pour le moment."

    lines = [
        "📈 Statistiques MasterMind",
        "=" * 40,
        f" Parties jouées: {summary['total_games']}",
        f" Victoires: {summary['games_won']}",
        f" Taux de victoire: {summary['win_rate']}%",
        f" Tentatives moyennes (victoires): {summary['avg_attempts']}",
        f" Meilleure victoire: {summary['best_victory']} tentative(s)" if summary['best_victory'] else " Aucune victoire pour le moment",
        f" Win rate (10 dernières): {summary['recent_win_rate']}%",
        "=" * 40
    ]
    return "\n".join(lines)
