from pydantic import BaseModel, Field, field_validator
from typing import Optional, Literal
import zoneinfo


class UserPreferencesResponse(BaseModel):
    date_format: str
    time_format: str
    timezone: str
    language: str
    currency_display: str
    notifications_email: bool
    notifications_sms: bool

    class Config:
        from_attributes = True


_ALLOWED_DATE_FORMATS = {
    "MM/DD/YYYY", "DD/MM/YYYY",
    "MM-DD-YYYY", "DD-MM-YYYY", "YYYY-MM-DD",
    # slash variants kept for backwards-compatibility
    "YYYY/MM/DD", "YYYY/DD/MM",
}
_ALLOWED_TIME_FORMATS = {"12h", "24h"}
_ALLOWED_CURRENCY_DISPLAYS = {"symbol", "code", "name"}
_ALLOWED_LANGUAGES = {"en", "es", "fr", "de", "pt"}


class UserPreferencesUpdate(BaseModel):
    date_format: Optional[str] = Field(None, max_length=20)
    time_format: Optional[str] = Field(None, max_length=5)
    timezone: Optional[str] = Field(None, max_length=64)
    language: Optional[str] = Field(None, max_length=10)
    currency_display: Optional[str] = Field(None, max_length=20)
    notifications_email: Optional[bool] = None
    notifications_sms: Optional[bool] = None

    @field_validator("date_format", mode="before")
    @classmethod
    def validate_date_format(cls, v: Optional[str]) -> Optional[str]:
        if v is not None and v not in _ALLOWED_DATE_FORMATS:
            raise ValueError(f"date_format must be one of: {sorted(_ALLOWED_DATE_FORMATS)}")
        return v

    @field_validator("time_format", mode="before")
    @classmethod
    def validate_time_format(cls, v: Optional[str]) -> Optional[str]:
        if v is not None and v not in _ALLOWED_TIME_FORMATS:
            raise ValueError(f"time_format must be one of: {sorted(_ALLOWED_TIME_FORMATS)}")
        return v

    @field_validator("timezone", mode="before")
    @classmethod
    def validate_timezone(cls, v: Optional[str]) -> Optional[str]:
        if v is not None:
            try:
                zoneinfo.ZoneInfo(v)
            except (zoneinfo.ZoneInfoNotFoundError, KeyError):
                raise ValueError(f"'{v}' is not a valid IANA timezone.")
        return v

    @field_validator("language", mode="before")
    @classmethod
    def validate_language(cls, v: Optional[str]) -> Optional[str]:
        if v is not None and v not in _ALLOWED_LANGUAGES:
            raise ValueError(f"language must be one of: {sorted(_ALLOWED_LANGUAGES)}")
        return v

    @field_validator("currency_display", mode="before")
    @classmethod
    def validate_currency_display(cls, v: Optional[str]) -> Optional[str]:
        if v is not None and v not in _ALLOWED_CURRENCY_DISPLAYS:
            raise ValueError(f"currency_display must be one of: {sorted(_ALLOWED_CURRENCY_DISPLAYS)}")
        return v
