"""
Bộ Theo Dõi Phiên Chơi & Lượt Chạy Bản Đồ (Live Session & Run Tracker)
Ghi nhận thời gian hoàn thành (Clear Time), số lần tử vong, quái tiêu diệt và lịch sử cày cuốc.
"""

import json
import logging
import os
import time
from dataclasses import asdict, dataclass
from typing import Callable, Dict, List, Optional

logger = logging.getLogger("RunTracker")


@dataclass
class MapRunRecord:
    run_id: int
    area_name: str
    area_level: int
    start_time: float
    end_time: float = 0.0
    duration_seconds: float = 0.0
    deaths_count: int = 0
    monsters_killed: int = 0
    status: str = "IN_PROGRESS"  # IN_PROGRESS, COMPLETED, DIED, ABORTED
    peak_dps: float = 0.0


class RunTracker:
    """
    Quản lý phiên chơi thời gian thực và lịch sử chạy map.
    """

    def __init__(self, history_file: str = "captures/run_history.json"):
        self.history_file = history_file
        self.current_run: Optional[MapRunRecord] = None
        self.run_history: List[MapRunRecord] = []
        self._next_run_id = 1
        self.total_deaths_all_time = 0
        self._on_run_complete_callbacks: List[Callable[[MapRunRecord], None]] = []
        self._load_history()

    def register_run_complete_listener(self, cb: Callable[[MapRunRecord], None]) -> None:
        self._on_run_complete_callbacks.append(cb)

    def on_zone_change(self, area_name: str, area_level: int = 0) -> Optional[MapRunRecord]:
        """
        Xử lý khi người chơi đổi khu vực.
        """
        now = time.time()
        completed_run = None

        is_town_or_hideout = any(
            t in area_name.lower()
            for t in ["hideout", "town", "encampment", "settlement", "sanctum", "relic", "shores"]
        )

        # 1. Kết thúc run hiện tại nếu về thành/hideout hoặc đổi map mới
        if self.current_run and self.current_run.status == "IN_PROGRESS":
            self.current_run.end_time = now
            self.current_run.duration_seconds = round(now - self.current_run.start_time, 1)

            if is_town_or_hideout:
                self.current_run.status = "COMPLETED"
            else:
                self.current_run.status = "TRANSITIONED"

            completed_run = self.current_run
            self.run_history.append(self.current_run)
            self._save_history()

            for cb in self._on_run_complete_callbacks:
                try:
                    cb(completed_run)
                except Exception as e:
                    logger.error(f"[RunTracker] Lỗi callback run complete: {e}")

            self.current_run = None

        # 2. Khởi tạo run mới nếu bước vào vùng quái (không phải thành)
        if not is_town_or_hideout and area_name:
            self.current_run = MapRunRecord(
                run_id=self._next_run_id,
                area_name=area_name,
                area_level=area_level,
                start_time=now,
                status="IN_PROGRESS"
            )
            self._next_run_id += 1
            logger.info(f"[RunTracker] Khởi động Lượt chạy #{self.current_run.run_id}: {area_name} (Level {area_level})")

        return completed_run

    def record_death(self) -> None:
        """Ghi nhận sự kiện người chơi tử trận trong run hiện tại."""
        self.total_deaths_all_time += 1
        if self.current_run:
            self.current_run.deaths_count += 1
            logger.warning(f"[RunTracker] Ghi nhận tử vong trong run #{self.current_run.run_id} ({self.current_run.area_name}).")

    def update_run_stats(self, peak_dps: float = 0.0, kill_increment: int = 0) -> None:
        """Cập nhật chỉ số chiến đấu liên tục cho run hiện tại."""
        if self.current_run:
            if peak_dps > self.current_run.peak_dps:
                self.current_run.peak_dps = peak_dps
            self.current_run.monsters_killed += kill_increment

    def get_current_run_duration(self) -> float:
        if self.current_run and self.current_run.start_time > 0:
            return round(time.time() - self.current_run.start_time, 1)
        return 0.0

    def get_session_summary(self) -> Dict[str, float]:
        """Tổng hợp thông số phiên chơi hiện tại."""
        total_runs = len(self.run_history)
        total_deaths = max(self.total_deaths_all_time, sum(r.deaths_count for r in self.run_history))

        if total_runs == 0:
            return {
                "total_runs": 0,
                "avg_clear_time": 0.0,
                "total_deaths": total_deaths,
                "fastest_clear": 0.0
            }

        completed_runs = [r for r in self.run_history if r.status in ["COMPLETED", "TRANSITIONED"] and r.duration_seconds > 10.0]

        if not completed_runs:
            return {
                "total_runs": total_runs,
                "avg_clear_time": 0.0,
                "total_deaths": total_deaths,
                "fastest_clear": 0.0
            }

        avg_time = sum(r.duration_seconds for r in completed_runs) / len(completed_runs)
        fastest_time = min(r.duration_seconds for r in completed_runs)

        return {
            "total_runs": total_runs,
            "avg_clear_time": round(avg_time, 1),
            "total_deaths": total_deaths,
            "fastest_clear": round(fastest_time, 1)
        }

    def _load_history(self) -> None:
        if os.path.exists(self.history_file):
            try:
                with open(self.history_file, "r", encoding="utf-8") as f:
                    data = json.load(f)
                    for item in data:
                        self.run_history.append(MapRunRecord(**item))
                if self.run_history:
                    self._next_run_id = max(r.run_id for r in self.run_history) + 1
            except Exception as e:
                logger.error(f"[RunTracker] Không thể đọc file history: {e}")

    def _save_history(self) -> None:
        os.makedirs(os.path.dirname(self.history_file) or ".", exist_ok=True)
        try:
            with open(self.history_file, "w", encoding="utf-8") as f:
                json.dump([asdict(r) for r in self.run_history[-200:]], f, indent=2, ensure_ascii=False)
        except Exception as e:
            logger.error(f"[RunTracker] Lỗi lưu history: {e}")
