from __future__ import annotations

import json
import os
import uuid
from datetime import datetime
from typing import Any


class RunStore:
    """File-based storage for game replays as JSON files.

    Each saved run is a self-contained JSON file with game configuration,
    move history, and computed statistics.
    """

    def __init__(self, runs_dir: str | None = None):
        if runs_dir is None:
            runs_dir = os.path.join(
                os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "runs"
            )
        self.runs_dir = os.path.abspath(runs_dir)
        os.makedirs(self.runs_dir, exist_ok=True)

    def save(self, session, name: str | None = None) -> str:
        """Save a GameSession as a replay file. Returns the run_id."""
        data = session.to_dict()

        if name is None:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            bot_type = data["config"]["bot_type"]
            name = f"{bot_type}_{timestamp}"

        run_id = f"{name}_{uuid.uuid4().hex[:8]}"
        filepath = os.path.join(self.runs_dir, f"{run_id}.json")

        run_data = {
            "run_id": run_id,
            "name": name,
            "created_at": datetime.now().isoformat(),
            "data": data,
        }

        with open(filepath, "w") as f:
            json.dump(run_data, f, indent=2)

        return run_id

    def list_runs(self) -> list[dict[str, Any]]:
        """List all saved runs with metadata, sorted by date (newest first)."""
        runs = []
        for filename in os.listdir(self.runs_dir):
            if not filename.endswith(".json"):
                continue
            filepath = os.path.join(self.runs_dir, filename)
            try:
                with open(filepath) as f:
                    run_data = json.load(f)
                config = run_data["data"]["config"]
                stats = run_data["data"].get("statistics", {})
                scores = run_data["data"].get("scores", [])
                runs.append(
                    {
                        "run_id": run_data["run_id"],
                        "name": run_data["name"],
                        "created_at": run_data["created_at"],
                        "board_size": config["board_size"],
                        "num_players": config["num_players"],
                        "human_player": config["human_player"],
                        "bot_type": config["bot_type"],
                        "game_over": run_data["data"]["game_over"],
                        "winner": run_data["data"]["winner"],
                        "scores": scores,
                        "total_moves": stats.get("total_moves", 0),
                        "coverage": stats.get("coverage", 0),
                    }
                )
            except (json.JSONDecodeError, KeyError):
                continue

        runs.sort(key=lambda r: r["created_at"], reverse=True)
        return runs

    def load(self, run_id: str) -> dict[str, Any] | None:
        """Load a run by ID. Returns the full run data dict, or None."""
        filepath = os.path.join(self.runs_dir, f"{run_id}.json")
        if not os.path.exists(filepath):
            return None

        with open(filepath) as f:
            return json.load(f)

    def delete(self, run_id: str) -> bool:
        """Delete a run by ID. Returns True if deleted, False if not found."""
        filepath = os.path.join(self.runs_dir, f"{run_id}.json")
        if os.path.exists(filepath):
            os.remove(filepath)
            return True
        return False
