"""
Wilderness Encounter Density & Dynamic Ambush Engine for FreeExile.
Enforces PoE2 spatial encounter rules, zone pack distributions,
and strict Safe Haven Firewall protection for Sanctuaries.
"""

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

try:
    from server.world.monster_types import (
        MonsterGenus,
        MonsterRank,
        ProceduralMonster,
        MonsterPack,
    )
    from server.world.monster_procedural_engine import MonsterProceduralEngine
    from server.world.zone_engine import ZoneEngine
except ImportError:
    from world.monster_types import (
        MonsterGenus,
        MonsterRank,
        ProceduralMonster,
        MonsterPack,
    )
    from world.monster_procedural_engine import MonsterProceduralEngine
    from world.zone_engine import ZoneEngine


class AmbushTriggerType(str, Enum):
    SHRINE = "SHRINE"
    CORRUPTED_RIFT = "CORRUPTED_RIFT"


@dataclass(slots=True)
class AmbushTrigger:
    trigger_id: str
    zone_id: str
    trigger_type: AmbushTriggerType
    x: float
    y: float
    trigger_radius: float = 3.5
    is_triggered: bool = False
    ambush_pack_size: int = 4
    entity_name: str = "Cổ Cốt Tế Đàn"


ZONE_DENSITY_SPECS: Dict[str, Dict] = {
    "zone_tang_kiem_nhai": {
        "name": "Bờ Đá Tàn Xương",
        "min_level": 1,
        "max_level": 8,
        "base_packs": 3,
        "native_genus": [
            MonsterGenus.FERAL_HELLHOUND,
            MonsterGenus.CORRUPTED_RAPTOR,
            MonsterGenus.RISEN_SKELETON,
        ],
        "ambushes": [
            AmbushTrigger(
                trigger_id="ambush_tang_kiem_shrine",
                zone_id="zone_tang_kiem_nhai",
                trigger_type=AmbushTriggerType.SHRINE,
                x=180.0,
                y=160.0,
                trigger_radius=3.5,
                ambush_pack_size=4,
                entity_name="Bát Mạch Linh Đài",
            ),
            AmbushTrigger(
                trigger_id="ambush_tang_kiem_rift",
                zone_id="zone_tang_kiem_nhai",
                trigger_type=AmbushTriggerType.CORRUPTED_RIFT,
                x=320.0,
                y=280.0,
                trigger_radius=4.0,
                ambush_pack_size=5,
                entity_name="Khe Nứt Hư Không",
            ),
        ],
    },
    "zone_ancient_sword_barrow": {
        "name": "Đầm Lầy Thối Rữa",
        "min_level": 8,
        "max_level": 20,
        "base_packs": 4,
        "native_genus": [
            MonsterGenus.BLOOD_CRAWLER,
            MonsterGenus.SHADOW_WRAITH,
            MonsterGenus.BRAMBLE_TREANT,
        ],
        "ambushes": [
            AmbushTrigger(
                trigger_id="ambush_ancient_sword_shrine",
                zone_id="zone_ancient_sword_barrow",
                trigger_type=AmbushTriggerType.SHRINE,
                x=250.0,
                y=260.0,
                trigger_radius=3.5,
                ambush_pack_size=4,
                entity_name="Huyết Tế Đàn",
            ),
        ],
    },
    "zone_boundless_sandstorm": {
        "name": "Sa Cốt Hoang Mạc",
        "min_level": 20,
        "max_level": 30,
        "base_packs": 5,
        "native_genus": [
            MonsterGenus.CORRUPTED_RAPTOR,
            MonsterGenus.IRONHIDE_BEHEMOTH,
            MonsterGenus.TOMB_LORD,
        ],
        "ambushes": [
            AmbushTrigger(
                trigger_id="ambush_sandstorm_rift",
                zone_id="zone_boundless_sandstorm",
                trigger_type=AmbushTriggerType.CORRUPTED_RIFT,
                x=400.0,
                y=420.0,
                trigger_radius=4.0,
                ambush_pack_size=5,
                entity_name="Cổ Cốt Hư Không Tháp",
            ),
        ],
    },
    "zone_blood_scale_ruins": {
        "name": "Phế Tích Xẻ Thịt",
        "min_level": 30,
        "max_level": 40,
        "base_packs": 6,
        "native_genus": [
            MonsterGenus.PRIMAL_CANNIBAL,
            MonsterGenus.FLESH_ABOMINATION,
            MonsterGenus.TOMB_LORD,
        ],
        "ambushes": [
            AmbushTrigger(
                trigger_id="ambush_blood_scale_shrine",
                zone_id="zone_blood_scale_ruins",
                trigger_type=AmbushTriggerType.SHRINE,
                x=350.0,
                y=350.0,
                trigger_radius=3.5,
                ambush_pack_size=5,
                entity_name="Bàn Thờ Quỷ Đoạt Mệnh",
            ),
        ],
    },
}


class WildernessEncounterEngine:
    """Authoritative engine for wilderness pack distribution and dynamic ambushes."""

    def __init__(
        self,
        zone_engine: Optional[ZoneEngine] = None,
        procedural_engine: Optional[MonsterProceduralEngine] = None,
    ) -> None:
        self.zone_engine = zone_engine if zone_engine is not None else ZoneEngine()
        self.procedural_engine = (
            procedural_engine
            if procedural_engine is not None
            else MonsterProceduralEngine()
        )
        self._triggers: Dict[str, Dict[str, AmbushTrigger]] = {}
        self._init_triggers()

    def _init_triggers(self) -> None:
        """Loads default ambush triggers from zone density specs."""
        for z_id, spec in ZONE_DENSITY_SPECS.items():
            self._triggers[z_id] = {}
            for trig in spec.get("ambushes", []):
                self._triggers[z_id][trig.trigger_id] = AmbushTrigger(
                    trigger_id=trig.trigger_id,
                    zone_id=trig.zone_id,
                    trigger_type=trig.trigger_type,
                    x=trig.x,
                    y=trig.y,
                    trigger_radius=trig.trigger_radius,
                    is_triggered=trig.is_triggered,
                    ambush_pack_size=trig.ambush_pack_size,
                    entity_name=trig.entity_name,
                )

    def register_trigger(self, trigger: AmbushTrigger) -> None:
        """Registers a custom or procedural ambush trigger."""
        if trigger.zone_id not in self._triggers:
            self._triggers[trigger.zone_id] = {}
        self._triggers[trigger.zone_id][trigger.trigger_id] = trigger

    def get_zone_density_spec(self, zone_id: str) -> Optional[Dict]:
        """Returns density specifications for a given zone."""
        return ZONE_DENSITY_SPECS.get(zone_id)

    def generate_zone_encounter_packs(
        self,
        zone_id: str,
        map_tier: Optional[int] = None,
        seed: int = 1000,
    ) -> List[MonsterPack]:
        """
        Generates packs for outer wilderness zones or map device instances.
        Enforces 0 spawns in Safe Haven Sanctuaries.
        """
        if not self.zone_engine.can_spawn_hostile_monsters(zone_id):
            return []

        spec = self.get_zone_density_spec(zone_id)
        base_packs = spec.get("base_packs", 3) if spec else 3
        native_genus = spec.get("native_genus", None) if spec else None
        if map_tier is not None:
            tier_bonus = max(0, (map_tier - 1) // 3)
            total_packs = base_packs + tier_bonus
            avg_level = min(100, 68 + map_tier)
        elif spec:
            total_packs = base_packs
            avg_level = (spec["min_level"] + spec["max_level"]) // 2
        else:
            total_packs = base_packs
            avg_level = 10

        packs: List[MonsterPack] = []
        for i in range(total_packs):
            pack_seed = seed + i * 773
            pack_id = f"pack_{zone_id}_{i + 1}"
            cx = 40.0 + (pack_seed % 300) * 1.5
            cy = 40.0 + ((pack_seed // 7) % 300) * 1.5
            pack_lvl = spec["min_level"] if (spec and i == 0 and spec["min_level"] == 1) else avg_level
            pack = self.procedural_engine.generate_pack(
                pack_id=pack_id,
                zone_id=zone_id,
                level=pack_lvl,
                center_x=cx,
                center_y=cy,
                seed=pack_seed,
                allowed_genus=native_genus,
            )
            packs.append(pack)
        return packs

    def check_and_trigger_ambush(
        self,
        zone_id: str,
        trigger_id: str,
        player_x: float,
        player_y: float,
    ) -> Tuple[bool, str, List[ProceduralMonster]]:
        """
        Evaluates proximity to an ambush trigger and spawns an ambush pack if valid.
        Strictly enforces the Safe Haven Firewall: returns False with rejection message if in sanctuary.
        """
        # 1. Authoritative Safe Haven Firewall Gate
        if not self.zone_engine.can_spawn_hostile_monsters(zone_id):
            return (
                False,
                f"Nghiêm cấm kích hoạt phục kích trong khu vực An Toàn [{zone_id}] theo chuẩn PoE2!",
                [],
            )

        zone_trigs = self._triggers.get(zone_id, {})
        trigger = zone_trigs.get(trigger_id)
        if trigger is None:
            return False, f"Không tìm thấy cơ quan phục kích '{trigger_id}'.", []

        if trigger.is_triggered:
            return False, "Cơ quan phục kích đã được kích hoạt trước đó.", []

        dist = math.hypot(player_x - trigger.x, player_y - trigger.y)
        if dist > trigger.trigger_radius:
            return (
                False,
                f"Cự ly ({dist:.1f}m) vượt quá bán kính kích hoạt ({trigger.trigger_radius}m).",
                [],
            )

        # 2. Mark triggered & synthesize ambush pack
        trigger.is_triggered = True
        spec = self.get_zone_density_spec(zone_id)
        lvl = (spec["min_level"] + spec["max_level"]) // 2 if spec else 15

        minion_count = max(1, trigger.ambush_pack_size - 1)
        ambush_pack = self.procedural_engine.generate_pack(
            pack_id=f"ambush_{trigger.trigger_id}",
            zone_id=zone_id,
            level=lvl,
            center_x=trigger.x,
            center_y=trigger.y,
            seed=int(trigger.x * 100 + trigger.y),
            minion_count=minion_count,
        )

        all_mobs = [ambush_pack.leader] + ambush_pack.minions
        msg = f"Phục kích bùng nổ tại {trigger.entity_name}!"
        return True, msg, all_mobs
