import datetime
import json
from typing import Literal

import jwt
from pydantic import UUID4, AwareDatetime, BaseModel, Field, field_validator

from huesoporro import utils
from huesoporro.settings import Settings


class TwitchAuth(BaseModel):
    access_token: str
    refresh_token: str
    userinfo: dict


class ExternalAuth(BaseModel):
    credentials: dict
    type: Literal["twitch"] = "twitch"


class User(BaseModel):
    id: UUID4
    username: str
    external_auth: dict[Literal["twitch", "discord"], TwitchAuth]
    created_at: AwareDatetime = Field(default_factory=utils.get_utc_now)
    last_updated_at: AwareDatetime = Field(default_factory=utils.get_utc_now)

    def encode(
        self, settings: Settings | None = None, exclude_fields: set[str] | None = None
    ) -> str:
        s = settings or Settings.get()
        exclude_fields = exclude_fields or {"external_auth"}
        return jwt.encode(
            self.model_dump(exclude=exclude_fields, mode="json"),
            key=s.jwt_secret.get_secret_value(),
            algorithm="HS256",
        )

    @classmethod
    def decode(cls, token: str, settings: Settings | None = None) -> dict:
        s = settings or Settings.get()
        return jwt.decode(
            token, key=s.jwt_secret.get_secret_value(), algorithms=["HS256"]
        )

    @property
    def twitch_access_token(self):
        return self.external_auth["twitch"].access_token

    @property
    def twitch_refresh_token(self):
        return self.external_auth["twitch"].refresh_token

    @twitch_access_token.setter  # type: ignore[attr-defined,no-redef]
    def twitch_access_token(self, value):
        self.external_auth["twitch"].access_token = value

    @twitch_refresh_token.setter  # type: ignore[attr-defined,no-redef]
    def twitch_refresh_token(self, value):
        self.external_auth["twitch"].refresh_token = value

    def serialize_external_auth(self) -> str:
        """Return a JSON string with the inner pydantic model of external_auth serialized using model_dump"""

        return json.dumps({k: v.model_dump() for k, v in self.external_auth.items()})


class Chatbot(BaseModel):
    """A chatbot is an entity that holds settings for a given user, it is NOT tied to a channel.

    Attributes:
        id (UUID4): The unique identifier for the chatbot.
        user_id (UUID): The user_id of the user that owns the chatbot.
        automatic_generation_timer (int): The timer for automatic generation of quotes.
        automatic_quote_timer (int): The timer for automatic quotes.
        mods (list[str]): The list of mods for the chatbot.
    """

    id: UUID4
    user_id: UUID4
    automatic_generation_timer: int = 300
    automatic_quote_timer: int = 500
    created_at: AwareDatetime = Field(default_factory=utils.get_utc_now)
    last_updated_at: AwareDatetime = Field(default_factory=utils.get_utc_now)
    mods: list[str] = Field(default_factory=list)

    @property
    def mods_as_string(self):
        if not self.mods:
            return ""
        return ",".join(self.mods)

    @field_validator("mods", mode="before")
    @classmethod
    def format_mods_from_string(cls, v):
        if isinstance(v, str):
            return v.split(",")
        return v


class Quote(BaseModel):
    id: UUID4
    quote: str
    author: str
    channel_name: str
    is_active: bool = True
    created_at: datetime.datetime = Field(default_factory=utils.get_utc_now)
    last_updated_at: datetime.datetime = Field(default_factory=utils.get_utc_now)

    def as_pretty(self) -> str:
        return f"«{self.quote}» - {self.author}"

    def as_pretty_saved(self):
        return f"He añadido la cita «{self.quote}» de {self.author}"
