import abc
import enum
from datetime import datetime
from typing import Optional, List

from pydantic import BaseModel, Field


class Platform(str, enum.Enum):
    TWITCH = "twitch"
    KICK = "kick"
    YOUTUBE = "youtube"
    TWITTER = "x"
    REDDIT = "reddit"
    TIKTOK = "tiktok"
    DISCORD = "discord"
    FACEBOOK = "facebook"
    INSTAGRAM = "instagram"
    DIRECT = "direct"

    def __str__(self):
        return self.value


class ChatMessage(BaseModel, abc.ABC):
    @abc.abstractmethod
    def get_content(self) -> str:
        """Get the content of the chat message."""
        ...

    @abc.abstractmethod
    def get_timestamp(self) -> float:
        """Get the timestamp of the chat message."""
        ...

    @abc.abstractmethod
    def get_broadcaster_user_id(self) -> str:
        """Get the broadcaster user ID."""
        ...


class UserAccessTokenBase(BaseModel):
    user_id: int
    access_token: str
    refresh_token: Optional[str] = None
    expires_in: int
    token_type: str
    scope: Optional[List[str]] = None
    platform: Platform


class UserAccessTokenCreate(UserAccessTokenBase):
    """Model for creating a new access token."""

    # Inherits all fields from UserAccessTokenBase


class UserAccessTokenUpdate(BaseModel):
    """Model for updating an access token."""

    access_token: Optional[str] = None
    refresh_token: Optional[str] = None
    expires_in: Optional[int] = None
    token_type: Optional[str] = None
    scope: Optional[List[str]] = None
    platform: Optional[Platform] = None
    updated_at: Optional[datetime] = Field(default_factory=datetime.now)
    deleted_at: Optional[datetime] = None


class UserAccessToken(UserAccessTokenBase):
    """Model for an access token."""

    id: int
    user_id: int
    created_at: datetime
    updated_at: datetime
    deleted_at: Optional[datetime] = None

    def is_expired(self) -> bool:
        """
        Check if the access token is expired.

        Returns:
            bool: True if token is expired or will expire in < 60 seconds

        Note:
            Adds a 60-second buffer to refresh before actual expiration
        """
        from datetime import timedelta, timezone

        if not self.expires_in:
            return True

        reference_time = self.updated_at or self.created_at
        if not reference_time:
            return True

        # Calculate expiry time from the latest token update timestamp.
        expiry_time = reference_time + timedelta(seconds=self.expires_in)

        # Add 60-second buffer to refresh before actual expiration
        current_time = datetime.now(timezone.utc)
        buffer_time = timedelta(seconds=60)

        return current_time >= (expiry_time - buffer_time)


class AppAccessToken(BaseModel):
    access_token: str
    expires_in: int
    token_type: str
    created_at: datetime = Field(default_factory=datetime.now)
