"""
Town Portal and Safe Teleportation Domain Models for FreeExile.

Provides strictly typed enums and immutable slotted data structures
for PoE2-style hideout portals, safe teleportation channeling,
and anti-exploit quarantine states.
"""

from __future__ import annotations

import enum
import time
from dataclasses import dataclass, field
from typing import Any, Optional, Tuple


class TeleportChannelStatus(enum.Enum):
    """Channeling state machine statuses for player teleportation."""

    IDLE = "IDLE"
    PENDING = "PENDING"
    CHANNELING = "CHANNELING"
    COMPLETED = "COMPLETED"
    INTERRUPTED_MOVEMENT = "INTERRUPTED_MOVEMENT"
    INTERRUPTED_DAMAGE = "INTERRUPTED_DAMAGE"
    CANCELLED = "CANCELLED"


class PortalQuarantineStatus(enum.Enum):
    """Anti-exploit quarantine security gates for portal and teleport actions."""

    ALLOWED = "ALLOWED"
    BLOCKED_BOSS_FIGHT = "BLOCKED_BOSS_FIGHT"
    BLOCKED_SECRET_CHAMBER = "BLOCKED_SECRET_CHAMBER"
    BLOCKED_NO_PORTALS_LEFT = "BLOCKED_NO_PORTALS_LEFT"
    BLOCKED_QUEST_LOCKED = "BLOCKED_QUEST_LOCKED"


class TargetType(enum.Enum):
    """Authorized destination entity types for safe teleportation."""

    PARTY_MEMBER = "PARTY_MEMBER"
    FRIEND = "FRIEND"
    GUILDMATE = "GUILDMATE"
    TOWN_PORTAL = "TOWN_PORTAL"


class InterruptReason(enum.Enum):
    """Root cause classification for interrupted channeling actions."""

    INTERRUPT_MOVEMENT = "INTERRUPT_MOVEMENT"
    INTERRUPT_DAMAGE = "INTERRUPT_DAMAGE"
    INTERRUPT_MANUAL = "INTERRUPT_MANUAL"


@dataclass(slots=True, frozen=True)
class TownPortalLink:
    """PoE2-style 2-way town portal link bridging wilderness coordinates to hub."""

    portal_id: str
    owner_id: str
    wilderness_zone_id: str
    wilderness_x: float
    wilderness_y: float
    hub_zone_id: str = "zone_player_hideout"
    hub_x: float = 0.0
    hub_y: float = 0.0
    created_at: float = field(default_factory=time.time)
    is_active: bool = True
    remaining_uses: int = -1
    instance_id: str = ""

    # Backward-compatible property aliases
    @property
    def player_id(self) -> str:
        return self.owner_id

    @property
    def origin_zone(self) -> str:
        return self.wilderness_zone_id

    @property
    def origin_x(self) -> float:
        return self.wilderness_x

    @property
    def origin_y(self) -> float:
        return self.wilderness_y

    @property
    def hub_zone(self) -> str:
        return self.hub_zone_id

    def __getitem__(self, item: str) -> Any:
        """Support dict-style subscripting for backwards compatibility."""
        if item in ("player_id", "owner_id"):
            return self.owner_id
        if item in ("origin_zone", "wilderness_zone_id", "source_zone_id"):
            return self.wilderness_zone_id
        if item in ("origin_x", "wilderness_x", "source_x"):
            return self.wilderness_x
        if item in ("origin_y", "wilderness_y", "source_y"):
            return self.wilderness_y
        if item in ("hub_zone", "hub_zone_id", "target_zone_id"):
            return self.hub_zone_id
        if item in ("hub_x", "target_x"):
            return self.hub_x
        if item in ("hub_y", "target_y"):
            return self.hub_y
        if item == "is_active":
            return self.is_active
        if item == "portal_id":
            return self.portal_id
        if item == "instance_id":
            return self.instance_id
        if item == "remaining_uses":
            return self.remaining_uses
        if item == "created_at":
            return self.created_at
        raise KeyError(item)

    def __setitem__(self, key: str, value: Any) -> None:
        """Allow dict-style state mutability on slotted instance."""
        object.__setattr__(self, key, value)

    def get(self, key: str, default: Any = None) -> Any:
        try:
            return self[key]
        except KeyError:
            return default


@dataclass(slots=True, frozen=True)
class TeleportChannelSession:
    """State tracking container for an active 3.5s teleportation channel."""

    session_id: str
    player_id: str
    target_type: TargetType
    target_id: str
    start_time: float
    duration_seconds: float = 3.5
    initial_x: float = 0.0
    initial_y: float = 0.0
    status: TeleportChannelStatus = TeleportChannelStatus.CHANNELING
    target_zone_id: str = ""

    # Backward-compatible property aliases
    @property
    def channel_id(self) -> str:
        return self.session_id

    @property
    def caster_id(self) -> str:
        return self.player_id

    @property
    def caster_player_id(self) -> str:
        return self.player_id

    @property
    def target_player_id(self) -> str:
        return self.target_id

    @property
    def cast_time(self) -> float:
        return self.duration_seconds

    @property
    def duration_ms(self) -> int:
        return int(self.duration_seconds * 1000)

    def __getitem__(self, item: str) -> Any:
        """Support dict-style subscripting for backwards compatibility."""
        if item in ("channel_id", "session_id"):
            return self.session_id
        if item in ("caster_id", "player_id", "caster_player_id"):
            return self.player_id
        if item in ("target_id", "target_player_id"):
            return self.target_id
        if item == "target_type":
            return self.target_type
        if item == "start_time":
            return self.start_time
        if item in ("cast_time", "duration_seconds"):
            return self.duration_seconds
        if item in ("target_zone_id", "target_zone"):
            return self.target_zone_id
        if item == "initial_x":
            return self.initial_x
        if item == "initial_y":
            return self.initial_y
        if item == "status":
            return self.status
        raise KeyError(item)

    def __setitem__(self, key: str, value: Any) -> None:
        """Allow dict-style state mutability on slotted instance."""
        object.__setattr__(self, key, value)

    def get(self, key: str, default: Any = None) -> Any:
        try:
            return self[key]
        except KeyError:
            return default


class TeleportChannelResult(Tuple[bool, str]):
    """Tuple-compatible teleport channeling result supporting both unpacking and attribute access."""

    def __new__(cls, success: bool, value: str, channel_id: Optional[str] = None, reason: str = ""):
        return super().__new__(cls, (success, value))

    @property
    def success(self) -> bool:
        return self[0]

    @property
    def channel_id(self) -> Optional[str]:
        return self[1] if self[0] else None

    @property
    def reason(self) -> str:
        return self[1] if not self[0] else ""


class TownPortalResult(Tuple[bool, str, Optional[str]]):
    """Tuple-compatible town portal result supporting (success, message, portal_id) unpacking."""

    def __new__(cls, success: bool, message: str, portal_id: Optional[str] = None):
        return super().__new__(cls, (success, message, portal_id))

    @property
    def success(self) -> bool:
        return self[0]

    @property
    def message(self) -> str:
        return self[1]

    @property
    def portal_id(self) -> Optional[str]:
        return self[2]
