"""AutoPOE2 - Atlas Special Encounter Matcher & Value Evaluator (Doc 65 / Doc 69).
==================================================================================
Nhận diện và định giá các cơ chế đặc biệt xuất hiện trên các Node Atlas POE2 v0.5.5+:
- Breach, Ritual, Delirium, Expedition, Boss Citadels, Unique Maps, Atlas Questlines.
- Tính toán điểm ưu tiên (Encounter Priority Score) và đề xuất nạp Precursor Tablet tối ưu.

Tuân thủ nghiêm ngặt:
- Rule 1: Cold Path Tier 2.
- Rule 4: Module hóa, trần file < 500 dòng.
- Rule 8: Bất biến kiến trúc INV-ATLAS-FARM-NODE & INV-ATLAS-QUEST-PROG.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Dict, List, Optional, Set, Tuple


class EncounterType(str, Enum):
    """Phân loại các cơ chế và sự kiện đặc biệt trên Node Atlas."""
    BREACH = "BREACH"
    RITUAL = "RITUAL"
    DELIRIUM = "DELIRIUM"
    EXPEDITION = "EXPEDITION"
    CITADEL_GUARDIAN = "CITADEL_GUARDIAN"
    PINNACLE_BOSS = "PINNACLE_BOSS"
    UNIQUE_MAP = "UNIQUE_MAP"
    ATLAS_QUEST = "ATLAS_QUEST"
    PRECURSOR_AURA = "PRECURSOR_AURA"
    STANDARD = "STANDARD"


@dataclass(frozen=True)
class EncounterProfile:
    """Hồ sơ giá trị và độ nguy hiểm của một cơ chế."""
    encounter_type: EncounterType
    display_name: str
    base_value_weight: float             # Trọng số lợi nhuận cơ bản (1.0 -> 5.0)
    danger_level: float                  # Độ rủi ro (0.0 -> 1.0)
    recommended_tablets: Tuple[str, ...] # Tablet tương thích
    min_tier: int = 1


_ENCOUNTER_REGISTRY: Dict[EncounterType, EncounterProfile] = {
    EncounterType.ATLAS_QUEST: EncounterProfile(
        encounter_type=EncounterType.ATLAS_QUEST,
        display_name="Atlas Questline (+1 Passive Point)",
        base_value_weight=5.0,
        danger_level=0.3,
        recommended_tablets=(),
        min_tier=1,
    ),
    EncounterType.CITADEL_GUARDIAN: EncounterProfile(
        encounter_type=EncounterType.CITADEL_GUARDIAN,
        display_name="Citadel Guardian (One-Life Crisis Fragment)",
        base_value_weight=4.5,
        danger_level=0.7,
        recommended_tablets=("Boss Drop", "Crisis"),
        min_tier=15,
    ),
    EncounterType.DELIRIUM: EncounterProfile(
        encounter_type=EncounterType.DELIRIUM,
        display_name="Delirium Mirror (Simulacrum Splinters & Cluster Jewels)",
        base_value_weight=3.2,
        danger_level=0.5,
        recommended_tablets=("Delirium", "Precursor"),
        min_tier=10,
    ),
    EncounterType.BREACH: EncounterProfile(
        encounter_type=EncounterType.BREACH,
        display_name="Breach Portal (Classified Splinters & Catalysts)",
        base_value_weight=3.0,
        danger_level=0.4,
        recommended_tablets=("Breach", "Precursor"),
        min_tier=8,
    ),
    EncounterType.RITUAL: EncounterProfile(
        encounter_type=EncounterType.RITUAL,
        display_name="Ritual Altar (Tribute & Deferral High Currency)",
        base_value_weight=2.8,
        danger_level=0.35,
        recommended_tablets=("Ritual", "Precursor"),
        min_tier=6,
    ),
    EncounterType.EXPEDITION: EncounterProfile(
        encounter_type=EncounterType.EXPEDITION,
        display_name="Expedition Excavation (Logbooks & Artifacts)",
        base_value_weight=2.7,
        danger_level=0.45,
        recommended_tablets=("Expedition", "Precursor"),
        min_tier=6,
    ),
    EncounterType.UNIQUE_MAP: EncounterProfile(
        encounter_type=EncounterType.UNIQUE_MAP,
        display_name="Unique Map (+2 Atlas Points First Clear)",
        base_value_weight=4.0,
        danger_level=0.6,
        recommended_tablets=(),
        min_tier=1,
    ),
    EncounterType.PRECURSOR_AURA: EncounterProfile(
        encounter_type=EncounterType.PRECURSOR_AURA,
        display_name="Precursor Tower Aura Coverage",
        base_value_weight=2.0,
        danger_level=0.2,
        recommended_tablets=("Delirium", "Breach", "Ritual"),
        min_tier=1,
    ),
    EncounterType.STANDARD: EncounterProfile(
        encounter_type=EncounterType.STANDARD,
        display_name="Standard Waystone Map",
        base_value_weight=1.0,
        danger_level=0.1,
        recommended_tablets=(),
        min_tier=1,
    ),
}


class EncounterMatcher:
    """Bộ nhận diện và tính toán giá trị cơ chế trên Node Atlas."""

    @staticmethod
    def identify_encounter(name_or_tag: str) -> EncounterProfile:
        """Nhận diện loại cơ chế từ chuỗi text hoặc thẻ tag."""
        t = name_or_tag.lower()
        if "quest" in t or "enigma" in t or "nexus" in t or "great beast" in t or "willow" in t or "kingsmarch" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.ATLAS_QUEST]
        if "citadel" in t or "geonor" in t or "jamanra" in t or "doryani" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.CITADEL_GUARDIAN]
        if "delirium" in t or "mirror of delirium" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.DELIRIUM]
        if "breach" in t or "xesht" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.BREACH]
        if "ritual" in t or "altar" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.RITUAL]
        if "expedition" in t or "kalguur" in t or "logbook" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.EXPEDITION]
        if "unique" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.UNIQUE_MAP]
        if "tower" in t or "aura" in t:
            return _ENCOUNTER_REGISTRY[EncounterType.PRECURSOR_AURA]
        return _ENCOUNTER_REGISTRY[EncounterType.STANDARD]

    @classmethod
    def calculate_score(
        cls,
        encounters: List[str],
        tower_coverage: int = 0,
        preferred_encounters: Optional[List[str]] = None,
    ) -> float:
        """
        Tính điểm thưởng tổng hợp dựa trên các cơ chế hiện diện trên node.
        Score = sum(base_value_weight * preference_multiplier) + (tower_coverage * 0.5)
        """
        pref_set = {p.lower() for p in (preferred_encounters or [])}
        total_score = 1.0

        for enc_tag in encounters:
            profile = cls.identify_encounter(enc_tag)
            multiplier = 1.5 if (profile.encounter_type.value.lower() in pref_set or enc_tag.lower() in pref_set) else 1.0
            total_score += profile.base_value_weight * multiplier

        if tower_coverage > 0:
            total_score += tower_coverage * 0.75

        return round(total_score, 2)
