"""
Player Private Hideout (Tiên Phủ Động Thiên) & Waygate Infrastructure Engine for FreeExile.
Architected following Path of Exile 2 (PoE2) Player Hideout & Endgame Map Device specifications.

Core Subsystems:
1. Private Sanctuary Instance: 100% Zero-Trust Server-Authoritative private world instance.
2. Astral Map Device (Thiên Đạo Tinh Đồ Nghi):
   - Accepts Tier 1 to Tier 16 Astral Map Tablets.
   - Summons 6 active Swirling Void Portals in a hexagonal ring around the device altar.
   - Each portal traversal consumes 1 portal charge (6 -> 5 -> ... -> 0).
3. World Exploration Waygate (Vạn Giới Giới Môn):
   - Configurable portal link to any of the 10 Canonical Open World Zones.
4. Quest & Bounty Portal (Thiên Mệnh Bí Cảnh Môn):
   - Synchronizes with active quests (Story Chapters, Boss Bounties, Cryptic Chambers).
   - Instant direct teleportation to the target quest objective area.
5. Interactive Hideout Facilities:
   - Consignment Vault & Seasonal Stash (Remove-Only Tab Consolidation).
   - Primal Spirit Stone Alchemy Cauldron & Forge.
   - Meridian Meditation Mat (Bát Mạch Đồ Đàn).
   - AI Agent Orb Delegation Altar (Phân Thần Tu Luyện).
"""

from __future__ import annotations
import math
import time
import uuid
from enum import Enum
from typing import Dict, List, Optional, Tuple, Any
from dataclasses import dataclass, field


class HideoutTheme(Enum):
    ASTRAL_PEAK = "ASTRAL_PEAK"            # Thái Hư Tiên Phong
    DRAGON_VALLEY = "DRAGON_VALLEY"        # Cổ Long U Cốc
    BAMBOO_SHRINE = "BAMBOO_SHRINE"        # Tiêu Dao Trúc Uyển (VLTK1 Classic)
    LUNAR_SANCTUARY = "LUNAR_SANCTUARY"    # Minh Nguyệt Hàn Đàm


class HideoutPortalType(Enum):
    MAP_DEVICE_PORTAL = "MAP_DEVICE_PORTAL"
    WORLD_EXPLORATION_GATE = "WORLD_EXPLORATION_GATE"
    QUEST_BOUNTY_GATE = "QUEST_BOUNTY_GATE"


class FacilityType(Enum):
    CONSIGNMENT_STASH_VAULT = "CONSIGNMENT_STASH_VAULT"
    PRIMAL_FORGE_CAULDRON = "PRIMAL_FORGE_CAULDRON"
    MERIDIAN_MEDITATION_MAT = "MERIDIAN_MEDITATION_MAT"
    AGENT_ORB_ALTAR = "AGENT_ORB_ALTAR"
    ASTRAL_MAP_DEVICE = "ASTRAL_MAP_DEVICE"


@dataclass(slots=True, frozen=True)
class AstralMap:
    map_id: str
    name: str
    tier: int                               # 1 to 16
    zone_template_id: str
    item_quantity_bonus_pct: int = 35       # +35% Drop Quantity
    item_rarity_bonus_pct: int = 20         # +20% Drop Rarity
    monster_pack_size_pct: int = 15         # +15% Pack Size
    boss_name: str = "Thống Lĩnh Man Quỷ"
    affixes: Tuple[str, ...] = (
        "+25% Sát Thương Quái Vật Hỏa",
        "Quái Vật Kháng Hàn Băng +30%",
        "+40% Tốc Độ Di Chuyển Của Quái Tinh Anh"
    )


@dataclass(slots=True)
class MapDeviceState:
    device_id: str
    center_x: float = 0.0
    center_y: float = 0.0
    radius: float = 4.2                     # Ring radius for the 6 portals
    active_map: Optional[AstralMap] = None
    active_instance_id: Optional[str] = None
    total_portals: int = 6                  # PoE2 Standard: Exactly 6 Portals
    portals_remaining: int = 0
    portal_states: List[bool] = field(default_factory=lambda: [False] * 6)  # True if open
    activated_timestamp_ms: int = 0


@dataclass(slots=True)
class WorldGateState:
    gate_id: str
    center_x: float = -6.5
    center_y: float = 2.0
    target_zone_id: str = "zone_tang_kiem_nhai"
    target_zone_name: str = "Táng Kiếm Nhai"
    is_active: bool = True
    vortex_color: str = "#38bdf8"           # Cyan / Azure Wind


@dataclass(slots=True)
class QuestGateState:
    gate_id: str
    center_x: float = 6.5
    center_y: float = 2.0
    active_quest_id: Optional[str] = "quest_story_01_thuc_tinh"
    quest_title: str = "Thức Tỉnh Kiếm Tâm"
    target_zone_id: str = "zone_ancient_sword_barrow"
    target_zone_name: str = "Cổ Kiếm Trũng"
    target_objective_x: float = 120.0
    target_objective_y: float = 85.0
    is_active: bool = True
    vortex_color: str = "#fbbf24"           # Golden Destiny


@dataclass(slots=True)
class PlayerHideout:
    hideout_id: str
    owner_player_id: str
    theme: HideoutTheme
    spawn_x: float = 0.0
    spawn_y: float = -4.0                   # In front of main pavilion
    map_device: MapDeviceState = field(default_factory=lambda: MapDeviceState(device_id="map_device_primary"))
    world_gate: WorldGateState = field(default_factory=lambda: WorldGateState(gate_id="world_gate_primary"))
    quest_gate: QuestGateState = field(default_factory=lambda: QuestGateState(gate_id="quest_gate_primary"))
    created_timestamp_ms: int = field(default_factory=lambda: int(time.time() * 1000))
    visitors: Set[str] = field(default_factory=set)


# Known Canonical Open-World Zones Directory
CANONICAL_ZONES = {
    "zone_tang_kiem_nhai": {"name": "Bờ Đá Tàn Xương", "min_level": 1, "max_level": 10, "x": 50.0, "y": 50.0},
    "zone_ancient_sword_barrow": {"name": "Đầm Lầy Thối Rữa", "min_level": 8, "max_level": 20, "x": 60.0, "y": 45.0},
    "zone_boundless_sandstorm": {"name": "Sa Cốt Hoang Mạc", "min_level": 20, "max_level": 35, "x": 100.0, "y": 120.0},
    "zone_blood_scale_ruins": {"name": "Phế Tích Xẻ Thịt", "min_level": 30, "max_level": 45, "x": 80.0, "y": 140.0},
    "zone_five_elements_altar": {"name": "Tế Đàn Man Hoang", "min_level": 40, "max_level": 55, "x": 150.0, "y": 150.0},
    "zone_abyssal_ice_pond": {"name": "Vực Đầm Băng Độc", "min_level": 50, "max_level": 65, "x": 90.0, "y": 180.0},
    "zone_infinite_blood_rift": {"name": "Vực Đói Nuốt Chửng", "min_level": 60, "max_level": 75, "x": 200.0, "y": 210.0},
    "zone_purgatory_lava_cavern": {"name": "Miệng Lửa Nung Máu", "min_level": 70, "max_level": 85, "x": 160.0, "y": 250.0},
    "zone_boundless_celestial_palace": {"name": "Bệ Thờ Quỷ Đoạt Mệnh", "min_level": 85, "max_level": 100, "x": 250.0, "y": 250.0},
}


class HideoutEngine:
    """
    Authoritative Hideout Manager for FreeExile.
    Manages private sanctums, 6-portal map device mechanics, and routing gates.
    """

    def __init__(self) -> None:
        self._hideouts: Dict[str, PlayerHideout] = {}  # key: player_id

    def get_or_create_hideout(
        self,
        player_id: str,
        theme: HideoutTheme = HideoutTheme.BAMBOO_SHRINE
    ) -> PlayerHideout:
        """Retrieves an existing hideout or instantiates a new sanctum for the player."""
        if player_id in self._hideouts:
            return self._hideouts[player_id]

        hideout_id = f"ho_{uuid.uuid4().hex[:12]}"
        hideout = PlayerHideout(
            hideout_id=hideout_id,
            owner_player_id=player_id,
            theme=theme,
            map_device=MapDeviceState(device_id=f"dev_{hideout_id}"),
            world_gate=WorldGateState(gate_id=f"wgate_{hideout_id}"),
            quest_gate=QuestGateState(gate_id=f"qgate_{hideout_id}")
        )
        self._hideouts[player_id] = hideout
        return hideout

    def change_hideout_theme(self, player_id: str, new_theme: HideoutTheme) -> Tuple[bool, str]:
        """Modifies the aesthetic theme of the player's personal hideout."""
        hideout = self.get_or_create_hideout(player_id)
        hideout.theme = new_theme
        return True, f"Chuyển đổi cảnh quan Động Phủ sang [{new_theme.value}] thành công."

    def activate_map_device(
        self,
        player_id: str,
        astral_map: AstralMap
    ) -> Tuple[bool, str, List[Dict[str, Any]]]:
        """
        Activates the 6-Portal Astral Map Device (Thiên Đạo Tinh Đồ Nghi).
        Opens exactly 6 swirling portals around the dais perimeter in a hexagonal layout.
        """
        if astral_map.tier < 1 or astral_map.tier > 16:
            return False, f"Cấp độ Tinh Đồ (Tier {astral_map.tier}) không hợp lệ! Chỉ cho phép Tier 1-16.", []

        hideout = self.get_or_create_hideout(player_id)
        dev = hideout.map_device

        # Create isolated dungeon instance id
        instance_id = f"inst_map_{astral_map.map_id}_{uuid.uuid4().hex[:8]}"

        dev.active_map = astral_map
        dev.active_instance_id = instance_id
        dev.total_portals = 6
        dev.portals_remaining = 6
        dev.portal_states = [True] * 6
        dev.activated_timestamp_ms = int(time.time() * 1000)

        # Calculate hexagonal coordinates for all 6 portals
        portal_info_list: List[Dict[str, Any]] = []
        for i in range(6):
            angle = i * (2.0 * math.pi / 6.0)
            px = dev.center_x + dev.radius * math.cos(angle)
            py = dev.center_y + dev.radius * math.sin(angle)
            portal_info_list.append({
                "portal_index": i,
                "portal_id": f"{dev.device_id}_p{i}",
                "x": round(px, 2),
                "y": round(py, 2),
                "is_open": True,
                "tier": astral_map.tier,
                "map_name": astral_map.name,
                "color": "#a855f7"  # Void Purple
            })

        msg = (
            f"[THIÊN ĐẠO TINH ĐỒ NGHI] Kích hoạt thành công [{astral_map.name}] "
            f"(Tier {astral_map.tier})! Đã triệu hồi 6 Cổng Hư Không."
        )
        return True, msg, portal_info_list

    def enter_map_portal(
        self,
        player_id: str,
        portal_index: Optional[int] = None,
        zone_engine: Optional[Any] = None,
    ) -> Tuple[bool, str, Optional[Dict[str, Any]]]:
        """
        Enters an active Map Device portal.
        Consumes exactly 1 portal from the remaining 6 charges.
        When 0 portals remain, the map instance is sealed permanently.
        """
        if portal_index is not None and not isinstance(portal_index, int) and zone_engine is None:
            zone_engine = portal_index
            portal_index = None

        hideout = self.get_or_create_hideout(player_id)
        dev = hideout.map_device

        if not dev.active_map or dev.portals_remaining <= 0 or not dev.active_instance_id:
            return False, "Thiên Đạo Tinh Đồ Nghi hiện không có Cổng nào mở hoặc đã hết lượt vào (0/6)!", None

        # Choose portal index to close
        target_idx = -1
        if portal_index is not None and 0 <= portal_index < 6 and dev.portal_states[portal_index]:
            target_idx = portal_index
        else:
            # Pick first available open portal
            for i, is_open in enumerate(dev.portal_states):
                if is_open:
                    target_idx = i
                    break

        if target_idx == -1:
            return False, "Không tìm thấy Cổng khả dụng trên Tinh Đồ Nghi!", None

        # Consume 1 portal charge
        dev.portal_states[target_idx] = False
        dev.portals_remaining -= 1

        result = {
            "instance_id": dev.active_instance_id,
            "map_name": dev.active_map.name,
            "tier": dev.active_map.tier,
            "target_zone_template": dev.active_map.zone_template_id,
            "spawn_x": 0.0,
            "spawn_y": 0.0,
            "portals_remaining": dev.portals_remaining,
            "consumed_portal_index": target_idx
        }

        # If exhausted all 6 portals, close device and purge instance session from ZoneEngine
        if dev.portals_remaining == 0:
            if zone_engine is not None and hasattr(zone_engine, "active_instances"):
                if dev.active_instance_id and dev.active_instance_id in zone_engine.active_instances:
                    zone_engine.active_instances.pop(dev.active_instance_id, None)
            dev.active_map = None
            dev.active_instance_id = None
            msg = f"Đã bước qua cổng #{target_idx + 1}. Đây là CỔNG CUỐI CÙNG (0/6)! Tinh Đồ Nghi đã khép lại."
        else:
            msg = f"Đã bước qua cổng #{target_idx + 1}. Còn lại {dev.portals_remaining}/6 Cổng Tinh Đồ."

        return True, msg, result

    def create_map_instance_session(
        self,
        player_id: str,
        astral_map: AstralMap,
        zone_engine: Optional[Any] = None,
    ) -> Tuple[bool, str, Dict[str, Any]]:
        """
        Activates map device and optionally registers an isolated InstanceSession with ZoneEngine.
        """
        ok, msg, portals = self.activate_map_device(player_id, astral_map)
        if not ok:
            return False, msg, {}

        hideout = self.get_or_create_hideout(player_id)
        dev = hideout.map_device
        res = {
            "instance_id": dev.active_instance_id or f"inst_map_{astral_map.map_id}",
            "portals": portals,
            "map_name": astral_map.name,
            "tier": astral_map.tier,
        }

        if zone_engine is not None and hasattr(zone_engine, "active_instances"):
            from server.world.spatial_grid import SpatialGrid
            from server.world.zone_types import InstanceSession

            session = InstanceSession(
                instance_id=dev.active_instance_id or f"inst_map_{astral_map.map_id}",
                template_id=astral_map.map_id,
                instance_zone_id=astral_map.zone_template_id,
                leader_player_id=player_id,
                member_player_ids=[],
                current_layer=1,
                max_layers=1,
                lives_remaining=6,
                time_limit_sec=7200,
                start_timestamp_ms=int(time.time() * 1000),
                spatial_grid=SpatialGrid(cell_size=64.0),
            )
            zone_engine.active_instances[session.instance_id] = session

        return True, msg, res

    def configure_world_gate(
        self,
        player_id: str,
        target_zone_id: str
    ) -> Tuple[bool, str, Dict[str, Any]]:
        """
        Configures the World Exploration Waygate to open a rift to an open-world zone.
        """
        if target_zone_id not in CANONICAL_ZONES:
            return False, f"Vùng đất [{target_zone_id}] không tồn tại trên Thần Châu đại lục!", {}

        hideout = self.get_or_create_hideout(player_id)
        zone_meta = CANONICAL_ZONES[target_zone_id]

        wg = hideout.world_gate
        wg.target_zone_id = target_zone_id
        wg.target_zone_name = zone_meta["name"]
        wg.is_active = True

        gate_payload = {
            "gate_id": wg.gate_id,
            "x": wg.center_x,
            "y": wg.center_y,
            "target_zone_id": target_zone_id,
            "target_zone_name": zone_meta["name"],
            "spawn_x": zone_meta["x"],
            "spawn_y": zone_meta["y"],
            "min_level": zone_meta["min_level"],
            "vortex_color": wg.vortex_color
        }

        return True, f"Vạn Giới Giới Môn đã thiết lập kết nối tới [{zone_meta['name']}].", gate_payload

    def configure_quest_gate(
        self,
        player_id: str,
        quest_id: str,
        quest_title: str,
        target_zone_id: str,
        objective_x: float = 100.0,
        objective_y: float = 100.0
    ) -> Tuple[bool, str, Dict[str, Any]]:
        """
        Configures the Quest Waygate to direct the player directly to the quest objective area.
        """
        hideout = self.get_or_create_hideout(player_id)
        qg = hideout.quest_gate

        zone_name = CANONICAL_ZONES.get(target_zone_id, {}).get("name", "Vùng Đất Lưu Đày")

        qg.active_quest_id = quest_id
        qg.quest_title = quest_title
        qg.target_zone_id = target_zone_id
        qg.target_zone_name = zone_name
        qg.target_objective_x = objective_x
        qg.target_objective_y = objective_y
        qg.is_active = True

        gate_payload = {
            "gate_id": qg.gate_id,
            "x": qg.center_x,
            "y": qg.center_y,
            "quest_id": quest_id,
            "quest_title": quest_title,
            "target_zone_id": target_zone_id,
            "target_zone_name": zone_name,
            "target_x": objective_x,
            "target_y": objective_y,
            "vortex_color": qg.vortex_color
        }

        return True, f"Thiên Mệnh Bí Cảnh Môn đã đồng bộ nhiệm vụ [{quest_title}] tại [{zone_name}].", gate_payload

    def interact_facility(
        self,
        player_id: str,
        facility_type: FacilityType
    ) -> Tuple[bool, str, Dict[str, Any]]:
        """
        Handles interaction with domestic hideout facilities.
        """
        hideout = self.get_or_create_hideout(player_id)

        if facility_type == FacilityType.CONSIGNMENT_STASH_VAULT:
            return True, "Mở Rương Vạn Giới Kỳ Trân & Tab Luân Hồi thành công.", {
                "facility": "STASH",
                "can_withdraw": True,
                "can_deposit": True
            }
        elif facility_type == FacilityType.PRIMAL_FORGE_CAULDRON:
            return True, "Tiếp cận Luyện Đan Lô & Lò Đúc Linh Thạch sẵn sàng chế tác.", {
                "facility": "FORGE",
                "crafting_available": True
            }
        elif facility_type == FacilityType.MERIDIAN_MEDITATION_MAT:
            return True, "Ngồi vào Bát Mạch Đồ Đàn, khí huyết lưu thông, sẵn sàng đả thông huyệt vị.", {
                "facility": "MERIDIAN",
                "meditation_active": True
            }
        elif facility_type == FacilityType.AGENT_ORB_ALTAR:
            return True, "Kích hoạt Định Hồn Thần Châu Đài uỷ thác AI Agent tự động du hành.", {
                "facility": "AGENT_ORB",
                "delegation_ready": True
            }
        elif facility_type == FacilityType.ASTRAL_MAP_DEVICE:
            portals = hideout.map_device.portals_remaining
            return True, f"Thiên Đạo Tinh Đồ Nghi sẵn sàng (Cổng còn lại: {portals}/6).", {
                "facility": "MAP_DEVICE",
                "portals_remaining": portals
            }

        return False, "Công trình không xác định.", {}

    def get_hideout_summary(self, player_id: str) -> Dict[str, Any]:
        """Provides a structured overview of the player's hideout status."""
        h = self.get_or_create_hideout(player_id)
        dev = h.map_device
        wg = h.world_gate
        qg = h.quest_gate

        return {
            "hideout_id": h.hideout_id,
            "theme": h.theme.value,
            "map_device": {
                "active_map": dev.active_map.name if dev.active_map else None,
                "tier": dev.active_map.tier if dev.active_map else None,
                "portals_remaining": dev.portals_remaining,
                "total_portals": dev.total_portals,
                "portal_states": list(dev.portal_states)
            },
            "world_gate": {
                "target_zone_id": wg.target_zone_id,
                "target_zone_name": wg.target_zone_name,
                "is_active": wg.is_active
            },
            "quest_gate": {
                "quest_id": qg.active_quest_id,
                "quest_title": qg.quest_title,
                "target_zone_id": qg.target_zone_id,
                "target_zone_name": qg.target_zone_name,
                "is_active": qg.is_active
            }
        }
