"""
Presence WebSocket message schemas.

Provides typed messages for user presence including:
- Online/offline/away status
- Typing indicators
- User roster (who's online)
- Activity tracking

Usage:
    from lightwave.schema.pydantic.contracts.websockets.presence import (
        PresenceUpdateInbound,
        UserJoinedOutbound,
        PresenceRosterOutbound,
    )

    # User updates their status
    update = PresenceUpdateInbound.model_validate(raw_data)

    # Broadcast user joined
    joined = UserJoinedOutbound(
        user_id="user-123",
        user_name="John Doe",
        status="online",
    )
    await broadcast_to_team(joined.to_ws_json())
"""

from datetime import datetime
from typing import Literal

from pydantic import Field

from lightwave.schema.pydantic.contracts.websockets.base import WSMessage

# =============================================================================
# Enums
# =============================================================================

PresenceStatus = Literal["online", "away", "busy", "offline", "invisible"]
TypingContext = Literal["chat", "document", "comment", "call_sheet", "shot_list"]


# =============================================================================
# User Info Schema
# =============================================================================


class PresenceUser(WSMessage):
    """User presence information."""

    user_id: str = Field(..., description="User ID")
    user_name: str = Field(..., description="Display name")
    avatar_url: str | None = Field(None, description="Avatar URL")
    status: PresenceStatus = Field(..., description="Current status")
    custom_status: str | None = Field(None, max_length=100, description="Custom status text")
    last_seen: datetime | None = Field(None, description="Last activity timestamp")
    current_page: str | None = Field(None, description="Current page/location")


# =============================================================================
# Inbound Messages (Client -> Server)
# =============================================================================


class PresenceUpdateInbound(WSMessage):
    """
    Update user presence status.

    Client sends this when user changes their status.
    """

    type: Literal["presence.update"] = "presence.update"
    status: PresenceStatus = Field(..., description="New status")
    custom_status: str | None = Field(
        None,
        max_length=100,
        description="Custom status message",
    )
    current_page: str | None = Field(
        None,
        description="Current page URL or identifier",
    )


class PresenceTypingInbound(WSMessage):
    """
    User is typing in a context.

    Client sends this when user starts/stops typing.
    """

    type: Literal["presence.typing"] = "presence.typing"
    context_type: TypingContext = Field(..., description="Where user is typing")
    context_id: str = Field(..., description="ID of the context (chat, document, etc.)")
    is_typing: bool = Field(..., description="Whether typing is in progress")


class PresenceAwayInbound(WSMessage):
    """
    User went away (idle).

    Client sends this after period of inactivity.
    """

    type: Literal["presence.away"] = "presence.away"
    away_since: datetime = Field(
        default_factory=datetime.utcnow,
        description="When user went away",
    )
    auto_detected: bool = Field(True, description="Whether auto-detected vs manual")


class PresenceSubscribeInbound(WSMessage):
    """
    Subscribe to presence updates.

    Client sends this to receive presence updates for a team/channel.
    """

    type: Literal["presence.subscribe"] = "presence.subscribe"
    team_id: str | None = Field(None, description="Team to subscribe to")
    user_ids: list[str] | None = Field(
        None,
        description="Specific users to track (null = all in team)",
    )
    include_roster: bool = Field(
        True,
        description="Whether to send initial roster",
    )


# =============================================================================
# Outbound Messages (Server -> Client)
# =============================================================================


class UserJoinedOutbound(WSMessage):
    """
    User came online.

    Broadcast when a user connects or changes to online status.
    """

    type: Literal["presence.user_joined"] = "presence.user_joined"
    user_id: str = Field(..., description="User ID")
    user_name: str = Field(..., description="Display name")
    avatar_url: str | None = Field(None, description="Avatar URL")
    status: PresenceStatus = Field("online", description="Status")
    joined_at: datetime = Field(
        default_factory=datetime.utcnow,
        description="When user came online",
    )


class UserLeftOutbound(WSMessage):
    """
    User went offline.

    Broadcast when a user disconnects.
    """

    type: Literal["presence.user_left"] = "presence.user_left"
    user_id: str = Field(..., description="User ID")
    left_at: datetime = Field(
        default_factory=datetime.utcnow,
        description="When user went offline",
    )
    reason: Literal["disconnect", "timeout", "logout"] = Field(
        "disconnect",
        description="Reason for leaving",
    )


class UserTypingOutbound(WSMessage):
    """
    User is typing.

    Broadcast to others in the same context.
    """

    type: Literal["presence.user_typing"] = "presence.user_typing"
    user_id: str = Field(..., description="User who is typing")
    user_name: str = Field(..., description="Display name")
    context_type: TypingContext = Field(..., description="Where user is typing")
    context_id: str = Field(..., description="Context identifier")
    is_typing: bool = Field(..., description="Whether still typing")


class UserAwayOutbound(WSMessage):
    """
    User went away.

    Broadcast when user becomes idle.
    """

    type: Literal["presence.user_away"] = "presence.user_away"
    user_id: str = Field(..., description="User ID")
    away_since: datetime = Field(..., description="When user went away")


class PresenceRosterOutbound(WSMessage):
    """
    Full list of online users.

    Sent on subscribe or request.
    """

    type: Literal["presence.roster"] = "presence.roster"
    users: list[PresenceUser] = Field(
        default_factory=list,
        description="Online users",
    )
    team_id: str | None = Field(None, description="Team this roster is for")
    total_online: int = Field(0, ge=0, description="Total online count")
    updated_at: datetime = Field(
        default_factory=datetime.utcnow,
        description="Roster timestamp",
    )
