"""X (Twitter) account schemas — request, response, and patch.

Uses repo_core base classes:
    - ``BaseRequestSchema`` — inbound (extra="forbid")
    - ``BaseResponseSchema`` — outbound (from_attributes=True)
    - ``BasePatchSchema`` — partial updates

All business-rule validation lives here via Pydantic ``@field_validator``
decorators — no separate validator file needed.
"""

from __future__ import annotations

import re
import uuid
from datetime import datetime
from typing import Any, Literal

from pydantic import BaseModel, Field, field_validator, model_validator

from repo_core.base.schemas import BaseRequestSchema, BaseResponseSchema, BasePatchSchema

# ---------------------------------------------------------------------------
# Shared types
# ---------------------------------------------------------------------------

XAccountStatus = Literal[
    "active",
    "banned",
    "deactivated",
    "locked",
    "not_logged_in",
    "not_used",
    "suspended",
]

# ---------------------------------------------------------------------------
# Create
# ---------------------------------------------------------------------------

class CreateXAccountRequest(BaseRequestSchema):
    """Payload for registering a new X (Twitter) account.

    At least one of ``email`` or ``mobile`` must be provided.
    """

    username: str = Field(..., min_length=1, max_length=128)
    password: str = Field(..., min_length=1)
    email: str | None = None
    mobile: str | None = None
    account_id: str | None = None
    display_name: str | None = None
    viewport: dict[str, Any] = Field(
        default_factory=lambda: {"width": 1920, "height": 1080}
    )
    timezone: str = "UTC"
    locale: str = "en-US"
    geolocation: dict[str, Any] | None = None
    proxy_region: str | None = None
    metadata: dict[str, Any] = Field(default_factory=dict)
    status: XAccountStatus = "active"

    @model_validator(mode="after")
    def _email_or_mobile_required(self) -> "CreateXAccountRequest":
        if not self.email and not self.mobile:
            raise ValueError("At least one of 'email' or 'mobile' must be provided")
        return self

    @field_validator("username")
    @classmethod
    def _username_not_blank(cls, v: str) -> str:
        cleaned = v.strip()
        if not cleaned:
            raise ValueError("Username cannot be blank")
        return cleaned

    @field_validator("email")
    @classmethod
    def _email_valid_format(cls, v: str | None) -> str | None:
        if v is None:
            return v
        cleaned = v.strip()
        if not cleaned:
            return None
        if not re.match(r"^[^@\s]+@[^@\s]+\.[^@\s]+$", cleaned):
            raise ValueError(f"Invalid email format: {cleaned}")
        return cleaned

    @field_validator("mobile")
    @classmethod
    def _mobile_valid_format(cls, v: str | None) -> str | None:
        if v is None:
            return v
        cleaned = v.strip()
        if not cleaned:
            return None
        if not re.match(r"^\+?[1-9]\d{6,14}$", cleaned):
            raise ValueError(f"Invalid mobile format: {cleaned}")
        return cleaned

    @field_validator("password")
    @classmethod
    def _password_not_blank(cls, v: str) -> str:
        cleaned = v.strip()
        if not cleaned:
            raise ValueError("Password cannot be blank")
        return cleaned


# ---------------------------------------------------------------------------
# Response
# ---------------------------------------------------------------------------

class XAccountResponse(BaseResponseSchema):
    """X (Twitter) account API response."""

    id: uuid.UUID
    username: str
    email: str | None = None
    mobile: str | None = None
    account_id: str | None = None
    display_name: str | None = None
    viewport: dict[str, Any] = Field(default_factory=dict)
    timezone: str = "UTC"
    locale: str = "en-US"
    geolocation: dict[str, Any] | None = None
    proxy_region: str | None = None
    platform: str = "x"
    account_metadata: dict[str, Any] = Field(default_factory=dict)
    status: XAccountStatus = "active"
    last_active_at: datetime | None = None
    created_at: datetime | None = None
    updated_at: datetime | None = None


class XAccountListResponse(BaseModel):
    items: list[XAccountResponse]
    total: int
    limit: int
    offset: int


# ---------------------------------------------------------------------------
# Patch
# ---------------------------------------------------------------------------

class PatchXAccountRequest(BasePatchSchema):
    """Partial update payload for an X account.

    Only explicitly-set fields are included in the patch dict::

        patch = PatchXAccountRequest(status="suspended", proxy_region="US-CA")
        update_fields = patch.to_patch_dict()  # {"status": "suspended", "proxy_region": "US-CA"}
    """

    display_name: str | None = None
    email: str | None = None
    mobile: str | None = None
    viewport: dict[str, Any] | None = None
    timezone: str | None = None
    locale: str | None = None
    geolocation: dict[str, Any] | None = None
    proxy_region: str | None = None
    status: XAccountStatus | None = None
    account_metadata: dict[str, Any] | None = None
    account_id: str | None = None
