"""
FreeExile Social Engine: Canonical Types, Enums, and Data Transfer Objects.
Follows strict typing and immutable slotted dataclasses according to GEMINI.md.
"""

from __future__ import annotations
import enum
from dataclasses import dataclass
from typing import Any, Optional


class FriendshipStatus(enum.Enum):
    """Lifecycle status for player friendship relationships."""
    NONE = "NONE"
    PENDING_SENT = "PENDING_SENT"
    PENDING_RECEIVED = "PENDING_RECEIVED"
    ACCEPTED = "ACCEPTED"
    BLOCKED = "BLOCKED"


class PresenceStatus(enum.Enum):
    """Real-time online presence status."""
    OFFLINE = "OFFLINE"
    ONLINE = "ONLINE"
    IN_COMBAT = "IN_COMBAT"
    AWAY = "AWAY"


RESTRICTED_PRIVATE_ZONES: frozenset[str] = frozenset({
    "zone_player_hideout",
    "zone_secret_chamber",
    "zone_puzzle_tomb",
    "zone_boss_arena",
    "offline",
    "zone_none",
    "",
})


@dataclass(slots=True, frozen=True)
class SocialActionResponse:
    """Standard response model for social interactions and friend operations."""
    success: bool
    message: str
    action_code: str = "OK"


@dataclass(slots=True, frozen=True)
class FriendDTO:
    """Immutable data transfer object representing a friend with real-time presence."""
    player_id: str
    character_name: str
    level: int
    character_class: str = "Outcast"
    presence_status: PresenceStatus = PresenceStatus.OFFLINE
    zone_id: str = ""
    current_map_name: str = ""
    friend_note: str = ""
    last_seen_timestamp: float = 0.0

    def __init__(
        self,
        player_id: str,
        character_name: str = "",
        level: int = 1,
        character_class: Any = "Outcast",
        presence_status: Any = PresenceStatus.OFFLINE,
        zone_id: str = "",
        current_map_name: str = "",
        friend_note: str = "",
        last_seen_timestamp: float = 0.0,
        *,
        name: Optional[str] = None,
        note: Optional[str] = None,
        zone_name: Optional[str] = None,
        is_online: Optional[bool] = None,
        character_class_or_online: Any = None,
        presence_status_or_zone_id: Any = None,
        zone_id_or_zone_name: Optional[str] = None,
        current_map_name_or_note: Optional[str] = None,
        **kwargs: Any,
    ) -> None:
        if character_class_or_online is not None:
            character_class = character_class_or_online
        if presence_status_or_zone_id is not None:
            presence_status = presence_status_or_zone_id
        if zone_id_or_zone_name is not None:
            zone_id = zone_id_or_zone_name
        if current_map_name_or_note is not None:
            current_map_name = current_map_name_or_note

        actual_name = name or character_name or player_id
        actual_class = "Outcast"
        actual_status = PresenceStatus.OFFLINE
        actual_zone_id = zone_id
        actual_map_name = current_map_name
        actual_note = note or friend_note

        # Support alternate positional signature: (player_id, name, level, is_online: bool, zone_id, zone_name, note)
        if isinstance(character_class, bool):
            actual_status = PresenceStatus.ONLINE if character_class else PresenceStatus.OFFLINE
            actual_zone_id = str(presence_status)
            actual_map_name = str(zone_id)
            if current_map_name:
                actual_note = current_map_name
        else:
            if isinstance(character_class, str):
                actual_class = character_class
            if isinstance(presence_status, bool):
                actual_status = PresenceStatus.ONLINE if presence_status else PresenceStatus.OFFLINE
            elif isinstance(presence_status, PresenceStatus):
                actual_status = presence_status
            elif isinstance(presence_status, str):
                try:
                    actual_status = PresenceStatus[presence_status]
                except KeyError:
                    actual_status = PresenceStatus.ONLINE

        if is_online is not None:
            actual_status = PresenceStatus.ONLINE if is_online else PresenceStatus.OFFLINE
        if zone_name:
            actual_map_name = zone_name

        object.__setattr__(self, "player_id", player_id)
        object.__setattr__(self, "character_name", actual_name)
        object.__setattr__(self, "level", int(level))
        object.__setattr__(self, "character_class", actual_class)
        object.__setattr__(self, "presence_status", actual_status)
        object.__setattr__(self, "zone_id", actual_zone_id)
        object.__setattr__(self, "current_map_name", actual_map_name)
        object.__setattr__(self, "friend_note", actual_note)
        object.__setattr__(self, "last_seen_timestamp", float(last_seen_timestamp))

    @property
    def name(self) -> str:
        """Alias for character_name."""
        return self.character_name

    @property
    def note(self) -> str:
        """Alias for friend_note."""
        return self.friend_note

    @property
    def zone_name(self) -> str:
        """Alias for current_map_name."""
        return self.current_map_name

    @property
    def is_online(self) -> bool:
        """Convenience property indicating active presence."""
        return self.presence_status != PresenceStatus.OFFLINE


# Backwards compatibility alias
FriendPresenceDTO = FriendDTO


@dataclass(slots=True, frozen=True)
class GuildMemberPresenceDTO:
    """Immutable data transfer object for guild member presence & teleport eligibility."""
    player_id: str
    character_name: str
    role: str
    level: int
    presence_status: PresenceStatus = PresenceStatus.OFFLINE
    zone_id: str = ""
    is_teleport_targetable: bool = False

    def __init__(
        self,
        player_id: str,
        character_name: str = "",
        role: Any = "Huynh Đệ",
        level: Any = 1,
        presence_status: Any = PresenceStatus.OFFLINE,
        zone_id: str = "",
        is_teleport_targetable: Optional[bool] = None,
        *,
        name: Optional[str] = None,
        rank: Optional[str] = None,
        is_online: Optional[bool] = None,
        **kwargs: Any,
    ) -> None:
        actual_name = name or character_name or player_id
        actual_role = "Huynh Đệ"
        actual_level = 1
        actual_status = PresenceStatus.OFFLINE

        # Detect argument order: (player_id, name, level: int, rank: str, is_online: bool, zone_id: str)
        if isinstance(role, int) and isinstance(level, str):
            actual_level = role
            actual_role = level
        else:
            if isinstance(role, str):
                actual_role = role
            if isinstance(level, int):
                actual_level = level

        if rank:
            actual_role = rank

        if isinstance(presence_status, bool):
            actual_status = PresenceStatus.ONLINE if presence_status else PresenceStatus.OFFLINE
        elif isinstance(presence_status, PresenceStatus):
            actual_status = presence_status
        elif isinstance(presence_status, str):
            try:
                actual_status = PresenceStatus[presence_status]
            except KeyError:
                actual_status = PresenceStatus.ONLINE

        if is_online is not None:
            actual_status = PresenceStatus.ONLINE if is_online else PresenceStatus.OFFLINE

        is_online_bool = actual_status != PresenceStatus.OFFLINE
        if is_teleport_targetable is None:
            targetable = (
                is_online_bool
                and bool(zone_id)
                and zone_id not in RESTRICTED_PRIVATE_ZONES
                and not zone_id.startswith("secret_")
                and not zone_id.startswith("zone_secret")
            )
        else:
            targetable = is_teleport_targetable

        object.__setattr__(self, "player_id", player_id)
        object.__setattr__(self, "character_name", actual_name)
        object.__setattr__(self, "role", actual_role)
        object.__setattr__(self, "level", int(actual_level))
        object.__setattr__(self, "presence_status", actual_status)
        object.__setattr__(self, "zone_id", zone_id)
        object.__setattr__(self, "is_teleport_targetable", targetable)

    @property
    def name(self) -> str:
        """Alias for character_name."""
        return self.character_name

    @property
    def rank(self) -> str:
        """Alias for role."""
        return self.role

    @property
    def is_online(self) -> bool:
        """Convenience property for online check."""
        return self.presence_status != PresenceStatus.OFFLINE
