"""AutoPOE2 - Map Clear Evaluator (Doc 69 §3.4 / Stage 5 In-Map - SSoT 2026).
================================================================================
Bộ thẩm định tiêu chuẩn hoàn tất bản đồ tự hành chuẩn thương mại (V2):
- Bất biến INV-MAP-LEGITIMATE-CLEAR-V2:
  Loại bỏ triệt để hiện tượng đánh 1 con quái hoặc vào vùng vắng quái rồi kết luận map clear.
  Rào chắn CẤM THOÁT SỚM (Anti-Premature-Exit Interlock):
  Bản đồ CHỈ ĐƯỢC CÔNG NHẬN HOÀN TẤT khi thỏa mãn ĐỒNG THỜI cả 3 trụ cột bắt buộc:
    1. Trụ cột 1 (Duration Gate): Thời gian ở trong map >= min_duration_sec (mặc định 90s).
    2. Trụ cột 2 (Traverse Distance Gate): Quãng đường tuần tra thực tế >= min_traverse_units (mặc định 1200u).
    3. Trụ cột 3 (Objective Completion Gate): Đạt ít nhất 1 trong 2 mục tiêu:
       - Boss Slain: Map Boss đã bị tiêu diệt.
       - Fog Coverage: Tỷ lệ mở sương mù Minimap >= target_coverage (mặc định 80%).

Tuân thủ nghiêm ngặt:
- Rule 1: Python 3.11 Cold Path Tier 2.
- Rule 4: Module hóa độc lập trần file < 500 dòng.
- Rule 5: 100% dữ liệu telemetry và quang học thật.
- Bất biến: INV-MAP-LEGITIMATE-CLEAR-V2, INV-WASD-NO-BLIND-LMB.
"""

from __future__ import annotations

import math
from typing import Optional, Tuple

from src.assistant_tool.navigation.monster_density_heatmap import MonsterDensityHeatmap


class MapClearEvaluator:
    """Bộ thẩm định tiêu chí hoàn tất map chuẩn thương mại cho Stage 5 (V2 SSoT 2026).

    Bất biến INV-MAP-LEGITIMATE-CLEAR-V2:
    Loại bỏ triệt để hiện tượng đánh 1 đàn quái nhỏ đầu map rồi kết luận map clear.
    """

    def __init__(
        self,
        min_duration_sec: float = 90.0,
        target_coverage: float = 0.80,
        min_traverse_units: float = 1200.0,
        min_required_packs: int = 4,
        density_heatmap: Optional[MonsterDensityHeatmap] = None,
    ) -> None:
        """Khởi tạo bộ thẩm định hoàn tất bản đồ V2.

        Args:
            min_duration_sec: Thời lượng tối thiểu nhân vật phải ở trong map (mặc định 90s).
            target_coverage: Ngưỡng diện tích mở sương Minimap tối thiểu (mặc định 80% / 0.80).
            min_traverse_units: Tổng quãng đường di chuyển tối thiểu của nhân vật (mặc định 1200u).
            min_required_packs: Số bãi quái tối thiểu phải chạm trán (mặc định 4 bãi).
            density_heatmap: Bản đồ nhiệt mật độ quái vật theo dõi phân bố không gian và Boss.
        """
        self.min_duration_sec = min_duration_sec
        self.target_coverage = target_coverage
        self.min_traverse_units = min_traverse_units
        self.min_required_packs = min_required_packs
        self.density_heatmap = density_heatmap

        self.total_distance_traversed: float = 0.0
        self.last_pos: Optional[Tuple[float, float]] = None
        self.last_coverage_ratio: float = 0.0
        self.boss_slain: bool = False
        self.packs_encountered: int = 0
        self.quiet_start_time: Optional[float] = None

    def reset(self) -> None:
        """Đặt lại trạng thái cho phiên map mới."""
        self.total_distance_traversed = 0.0
        self.last_pos = None
        self.last_coverage_ratio = 0.0
        self.boss_slain = False
        self.packs_encountered = 0
        self.quiet_start_time = None
        if self.density_heatmap is not None:
            self.density_heatmap.reset()

    def update_optical_boss_status(
        self,
        boss_bar_detected: bool,
        health_ratio: float = 1.0,
        is_phased: bool = False,
    ) -> None:
        """Cập nhật dữ liệu thị giác về thanh máu Boss từ BossArenaDetector.

        Args:
            boss_bar_detected: True nếu phát hiện thanh máu Boss trên đỉnh màn hình.
            health_ratio: Tỷ lệ máu còn lại của Boss (0.0 .. 1.0).
            is_phased: True nếu Boss đang chuyển pha hoặc miễn nhiễm sát thương.
        """
        if self.density_heatmap is not None:
            self.density_heatmap.update_optical_boss_status(
                boss_bar_detected=boss_bar_detected,
                health_ratio=health_ratio,
                is_phased=is_phased,
            )
            if self.density_heatmap.boss_slain_optical:
                self.boss_slain = True
        elif boss_bar_detected and health_ratio <= 0.02:
            self.boss_slain = True

    def update_telemetry(
        self,
        pos_x: float,
        pos_y: float,
        monsters_near: int,
        coverage_ratio: float = 0.0,
        boss_slain: bool = False,
        now_sec: float = 0.0,
    ) -> None:
        """Cập nhật dữ liệu trắc viễn thời gian thực từ game và cảm biến.

        Args:
            pos_x: Tọa độ X của người chơi trong world coordinates.
            pos_y: Tọa độ Y của người chơi trong world coordinates.
            monsters_near: Số lượng quái vật sống trong bong bóng hiển thị cục bộ.
            coverage_ratio: Tỷ lệ diện tích sương mù đã mở (0.0 .. 1.0).
            boss_slain: True nếu phát hiện tín hiệu Boss bản đồ đã bị hạ gục.
            now_sec: Timestamp hiện tại (giây).
        """
        # 1. Tính toán quãng đường di chuyển tích lũy
        if self.last_pos is not None and (pos_x != 0.0 or pos_y != 0.0):
            dx = pos_x - self.last_pos[0]
            dy = pos_y - self.last_pos[1]
            dist = math.hypot(dx, dy)
            # Lọc nhiễu: Chỉ cộng dồn bước di chuyển hợp lệ (0.5u - 800u/nhịp)
            # Loại bỏ tọa độ dịch chuyển ảo do load cảnh hoặc lỗi đọc RAM
            if 0.5 <= dist <= 800.0:
                self.total_distance_traversed += dist

        if pos_x != 0.0 or pos_y != 0.0:
            self.last_pos = (pos_x, pos_y)

        # 2. Cập nhật tỷ lệ sương mù Minimap (chỉ tăng, không giảm)
        if coverage_ratio > self.last_coverage_ratio:
            self.last_coverage_ratio = coverage_ratio

        # 3. Cập nhật trạng thái tiêu diệt Boss
        if boss_slain:
            self.boss_slain = True

        # 4. Ghi nhận đàn quái vật đã chạm trán
        # Sửa lỗi: monsters_near >= 1 được tính là quái vật sống, reset quiet timer
        if monsters_near >= 1:
            self.packs_encountered += 1
            self.quiet_start_time = None
        elif monsters_near == 0 and now_sec > 0.0:
            if self.quiet_start_time is None:
                self.quiet_start_time = now_sec

        # 5. Đồng bộ hóa với Monster Density Heatmap nếu có
        if self.density_heatmap is not None:
            self.density_heatmap.record_telemetry_frame(
                player_x=pos_x,
                player_y=pos_y,
                monsters_near=monsters_near,
                now_sec=now_sec,
            )
            if self.density_heatmap.boss_slain_optical:
                self.boss_slain = True
            self.packs_encountered = max(self.packs_encountered, self.density_heatmap.total_packs_count)

    def evaluate_clear(
        self,
        elapsed_sec: float,
        core_lifecycle_state: Optional[int] = None,
        now_sec: float = 0.0,
    ) -> Tuple[bool, str]:
        """Thẩm định xem bản đồ đã thực sự hoàn tất hay chưa (INV-MAP-LEGITIMATE-CLEAR-V2).

        Rào chắn CẤM THOÁT SỚM: BẮT BUỘC THỎA MÃN ĐỒNG THỜI CÁC TRỤ CỘT:
          1. Thời gian ở trong map >= min_duration_sec (>= 90s)
          2. Quãng đường tuần tra thực tế >= min_traverse_units (>= 1200u)
          3. Thẩm định bãi quái hợp lệ >= min_required_packs (>= 4 bãi hoặc >= 25 kills)
          4. Mục tiêu cốt lõi: (Mở sương Minimap >= target_coverage HOẶC Boss Slain)

        Args:
            elapsed_sec: Thời gian đã trôi qua kể từ khi vào map (giây).
            core_lifecycle_state: Trạng thái CharacterLifecycleState từ C++ Core SHM.
            now_sec: Timestamp hiện tại.

        Returns:
            Tuple[bool, str]: (is_cleared, reason)
        """
        # =====================================================================
        # TRỤ CỘT 1: Thời lượng tối thiểu trong map (min_duration_sec >= 90s)
        # =====================================================================
        if elapsed_sec < self.min_duration_sec:
            return False, ""

        # =====================================================================
        # TRỤ CỘT 2: Quãng đường tuần tra thực tế (min_traverse_units >= 1200u)
        # Tuyệt đối cấm kết luận hoàn tất khi chỉ đứng yên hoặc di chuyển ngắn.
        # =====================================================================
        if self.total_distance_traversed < self.min_traverse_units:
            return False, ""

        # =====================================================================
        # TRỤ CỘT 3: Thẩm định bãi quái hợp lệ (INV-MAP-LEGITIMATE-CLEAR-V2)
        # Loại bỏ triệt để hiện tượng đánh 1 đàn quái nhỏ đầu map rồi kết luận clear.
        # Bắt buộc chạm trán >= min_required_packs (hoặc >= 25 kills qua heatmap).
        # =====================================================================
        if self.density_heatmap is not None:
            is_legit, _ = self.density_heatmap.is_clearing_legitimate(self.min_required_packs)
            if not is_legit:
                return False, ""
        else:
            if self.packs_encountered < self.min_required_packs:
                return False, ""

        # =====================================================================
        # TRỤ CỘT 4: Mục tiêu cốt lõi (Boss Slain HOẶC Độ phủ Minimap >= target_coverage)
        # Triệt tiêu lỗ hổng: đánh quái rồi đi vào ngõ cụt yên ắng (quiet area)
        # hoặc đi lòng vòng trong phòng đầu map nhưng chưa khám phá bản đồ.
        # =====================================================================
        has_objective = self.boss_slain or (self.last_coverage_ratio >= self.target_coverage)
        if not has_objective:
            return False, ""

        # =====================================================================
        # TẤT CẢ 3 TRỤ CỘT ĐỀU THỎA MÃN: XÁC LẬP BẰNG CHỨNG NGHIỆM THU RÕ RÀNG
        # =====================================================================
        MAP_COMPLETED_PORTAL_OUT = 9
        IN_MAP_PORTAL_EXIT = 11
        core_confirmed = core_lifecycle_state in (MAP_COMPLETED_PORTAL_OUT, IN_MAP_PORTAL_EXIT)

        # Trường hợp 1: Map Boss đã bị tiêu diệt
        if self.boss_slain:
            core_note = f" (Core State={core_lifecycle_state})" if core_confirmed else ""
            return (
                True,
                f"Map Boss đã bị tiêu diệt sau {int(elapsed_sec)}s "
                f"(Quãng đường tuần tra: {self.total_distance_traversed:.0f}u >= {self.min_traverse_units:.0f}u, "
                f"Sương mở: {self.last_coverage_ratio*100:.1f}%){core_note}"
            )

        # Trường hợp 2: Minimap đã mở sương mù toàn diện (>= target_coverage)
        if self.last_coverage_ratio >= self.target_coverage:
            quiet_note = ""
            if (
                self.quiet_start_time is not None
                and now_sec > 0.0
                and (now_sec - self.quiet_start_time >= 25.0)
            ):
                quiet_note = " và khu vực hoàn toàn yên ắng"

            core_note = f" (Core State={core_lifecycle_state})" if core_confirmed else ""
            return (
                True,
                f"Minimap đã mở sương đạt {self.last_coverage_ratio*100:.1f}% "
                f"(>= {self.target_coverage*100:.0f}%) sau {int(elapsed_sec)}s "
                f"(Quãng đường: {self.total_distance_traversed:.0f}u >= {self.min_traverse_units:.0f}u{quiet_note}){core_note}"
            )

        return False, ""
