# models/twitch_models.py
from datetime import datetime
from typing import List, Optional, Dict, Any

from pydantic import BaseModel, Field

import common.models.common


class MarkStreamRequest(BaseModel):
    user_id: str
    description: Optional[str] = None


class MarkStreamResponse(BaseModel):
    id: str
    created_at: datetime
    position_seconds: int
    description: str


class StreamMarker(BaseModel):
    id: str
    created_at: str
    description: str
    position_seconds: int
    URL: Optional[str] = None


class VideoMarkers(BaseModel):
    video_id: str
    markers: List[StreamMarker]


class UserMarkers(BaseModel):
    user_id: str
    user_name: str
    user_login: str
    videos: List[VideoMarkers]


class GetStreamMarkersResponse(BaseModel):
    data: List[UserMarkers]
    pagination: dict = Field(default_factory=dict)


class User(BaseModel):
    id: str
    login: str
    display_name: str
    type: str
    broadcaster_type: str
    description: str
    profile_image_url: str
    offline_image_url: str
    view_count: int
    email: Optional[str] = None  # Available if scopes include user:read:email


class ChannelInfo(BaseModel):
    broadcaster_id: str
    broadcaster_login: str
    broadcaster_name: str
    broadcaster_language: str
    game_id: str
    game_name: str
    title: str
    delay: int
    tags: List[str]
    content_classification_labels: List[str]
    is_branded_content: bool


class Stream(BaseModel):
    id: str
    user_id: str
    user_login: str
    user_name: str
    game_id: str
    game_name: str
    type: str
    title: str
    viewer_count: int
    started_at: str
    language: str
    thumbnail_url: str
    tag_ids: List[str]
    is_mature: bool


class EventSubTransport(BaseModel):
    method: str
    callback: Optional[str] = None
    secret: Optional[str] = None
    session_id: Optional[str] = None  # For WebSocket transports
    conduit_id: Optional[str] = None  # For Conduit transports


class EventSubSubscriptionRequest(BaseModel):
    type: str
    version: str
    condition: Dict[str, Any]
    transport: EventSubTransport


class EventSubSubscription(BaseModel):
    id: str
    status: str
    type: str
    version: str
    condition: Dict[str, Any]
    transport: Dict[str, Any]
    created_at: str
    cost: int


class EventSubNotification(BaseModel):
    subscription: EventSubSubscription
    event: Dict[str, Any]  # Structure depends on the subscription type


# New Models for Conduits
class EventSubConduit(BaseModel):
    id: str
    shard_count: int


class EventSubConduitShard(BaseModel):
    id: str
    transport: EventSubTransport
    status: Optional[str] = None
    connected_at: Optional[str] = None
    disconnected_at: Optional[str] = None


class EventSubConduitShardsUpdate(BaseModel):
    conduit_id: str
    shards: List[EventSubConduitShard]


class EventSubConduitShardsUpdateResponse(BaseModel):
    data: List[EventSubConduitShard]


class WebSocketSession(BaseModel):
    id: str
    status: str
    connected_at: str
    keepalive_timeout_seconds: Optional[int] = None
    reconnect_url: Optional[str] = None


class WebSocketMessageMetadata(BaseModel):
    message_id: str
    message_type: str
    message_timestamp: str
    subscription_type: Optional[str] = None
    subscription_version: Optional[str] = None


class WebSocketMessagePayload(BaseModel):
    subscription: Optional[EventSubSubscription] = None
    event: Optional[Dict[str, Any]] = None
    session: Optional[WebSocketSession] = None


class WebSocketMessage(BaseModel):
    metadata: WebSocketMessageMetadata
    payload: WebSocketMessagePayload


class TwitchChatMessageRequest(BaseModel):
    broadcaster_id: str
    sender_id: str
    message: str = Field(max_length=500)
    reply_parent_message_id: Optional[str] = None


class TwitchChatMessageDropReason(BaseModel):
    code: str
    message: str


class TwitchChatMessageResponse(BaseModel):
    message_id: str
    is_sent: bool
    drop_reason: Optional[TwitchChatMessageDropReason] = None


class MessageFragment(BaseModel):
    type: str
    text: str
    cheermote: Optional[Dict[str, Any]] = None
    emote: Optional[Dict[str, Any]] = None
    mention: Optional[Dict[str, Any]] = None


class Badge(BaseModel):
    set_id: str
    id: str
    info: str = ""


class MessageContent(BaseModel):
    text: str
    fragments: List[MessageFragment]


class TwitchChatMessage(common.models.common.ChatMessage):
    # Broadcaster info
    broadcaster_user_id: str
    broadcaster_user_login: str
    broadcaster_user_name: str

    # Chatter info
    chatter_user_id: str
    chatter_user_login: str
    chatter_user_name: str

    # Message data
    message_id: str
    message: MessageContent

    # Visual styles
    color: Optional[str] = None
    badges: List[Badge] = []

    # Message metadata
    message_type: str = "text"
    created_at: float

    # Additional fields
    cheer: Optional[Dict[str, Any]] = None
    reply: Optional[Dict[str, Any]] = None
    channel_points_custom_reward_id: Optional[str] = None

    # Source info (for replies/shares)
    source_broadcaster_user_id: Optional[str] = None
    source_broadcaster_user_login: Optional[str] = None
    source_broadcaster_user_name: Optional[str] = None
    source_message_id: Optional[str] = None
    source_badges: Optional[List[Badge]] = None

    def get_content(self) -> str:
        """Get the content of the chat message."""
        return self.message.text

    def get_timestamp(self) -> float:
        """Get the timestamp of the chat message."""
        return self.created_at

    def get_broadcaster_user_id(self) -> str:
        """Get the broadcaster user ID."""
        return self.broadcaster_user_id

    @classmethod
    def from_eventsub(cls, event: Dict[str, Any]) -> "TwitchChatMessage":
        """Create a TwitchChatMessage from an EventSub message event"""
        message_data = event.get("message", {})

        # Convert raw fragments to MessageFragment objects
        fragments = [
            MessageFragment(
                type=frag.get("type", "text"),
                text=frag.get("text", ""),
                cheermote=frag.get("cheermote"),
                emote=frag.get("emote"),
                mention=frag.get("mention"),
            )
            for frag in message_data.get("fragments", [])
        ]

        # Create MessageContent
        message = MessageContent(text=message_data.get("text", ""), fragments=fragments)

        # Convert badges
        badges = [
            Badge(
                set_id=badge.get("set_id", ""),
                id=badge.get("id", ""),
                info=badge.get("info", ""),
            )
            for badge in event.get("badges", [])
        ]

        # Convert source badges if present
        source_badges = None
        if event.get("source_badges"):
            source_badges = [
                Badge(
                    set_id=badge.get("set_id", ""),
                    id=badge.get("id", ""),
                    info=badge.get("info", ""),
                )
                for badge in event.get("source_badges", [])
            ]

        # cls.Meta.database = connect()

        c = cls(
            broadcaster_user_id=event.get("broadcaster_user_id"),
            broadcaster_user_login=event.get("broadcaster_user_login"),
            broadcaster_user_name=event.get("broadcaster_user_name"),
            chatter_user_id=event.get("chatter_user_id"),
            chatter_user_login=event.get("chatter_user_login"),
            chatter_user_name=event.get("chatter_user_name"),
            message_id=event.get("message_id"),
            message=message,
            color=event.get("color"),
            badges=badges,
            message_type=event.get("message_type", "text"),
            cheer=event.get("cheer"),
            reply=event.get("reply"),
            channel_points_custom_reward_id=event.get(
                "channel_points_custom_reward_id"
            ),
            source_broadcaster_user_id=event.get("source_broadcaster_user_id"),
            source_broadcaster_user_login=event.get("source_broadcaster_user_login"),
            source_broadcaster_user_name=event.get("source_broadcaster_user_name"),
            source_message_id=event.get("source_message_id"),
            source_badges=source_badges,
            created_at=datetime.now().timestamp(),
        )
        return c
