"""
Authentication schemas.

Pydantic models for login requests, token responses, and user profile representations.
"""

from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator


class LoginRequest(BaseModel):
    """Payload for user login with phone or email, and password."""

    phone: str | None = Field(
        default=None,
        max_length=255,
        description="Staff phone number (e.g. 9800000000)",
        examples=["9800000000"],
    )
    email: str | None = Field(
        default=None,
        max_length=255,
        description="Staff email address (e.g. admin@munal.com)",
        examples=["admin@munal.com"],
    )
    password: str = Field(
        ...,
        min_length=6,
        description="User password",
        examples=["AdminPassword123!"],
    )

    @model_validator(mode="after")
    def validate_identifier(self) -> "LoginRequest":
        if not self.phone and not self.email:
            raise ValueError("Either 'phone' or 'email' must be provided.")
        return self

    @property
    def identifier(self) -> str:
        """Resolve the login identifier from phone or email."""
        val = self.phone or self.email or ""
        return val.strip()


class TokenResponse(BaseModel):
    """Authentication token response with access and refresh tokens."""

    access_token: str
    refresh_token: str
    token_type: str = "bearer"
    expires_in: int = Field(..., description="Access token lifetime in seconds")


class RefreshRequest(BaseModel):
    """Payload to refresh an access token."""

    # Production browsers send an empty JSON object and use the HttpOnly cookie.
    # Explicit token values still receive the existing validation.
    refresh_token: str = Field(default="", min_length=10, description="Valid JWT refresh token")


class UserMeResponse(BaseModel):
    """Current authenticated user profile."""

    model_config = ConfigDict(from_attributes=True)

    id: UUID
    name: str
    phone: str
    email: str | None
    role: str
    lab_id: UUID
    is_active: bool
    license_no: str | None = Field(
        default=None, description="Professional council registration number (e.g. NMC No.)"
    )
    permissions: list[str] = Field(
        default_factory=list, description="Effective permission codes for this user"
    )


class BootstrapRequest(BaseModel):
    """Payload to bootstrap the initial laboratory branch and superadmin user."""

    lab_name: str = Field(
        default="Munal Central Lab",
        min_length=2,
        max_length=200,
        description="Name of the main laboratory branch",
    )
    admin_name: str = Field(
        ...,
        min_length=2,
        max_length=200,
        description="Superadmin full name",
    )
    admin_phone: str = Field(
        ...,
        min_length=7,
        max_length=20,
        description="Superadmin phone number (primary login identifier)",
    )
    admin_email: str | None = Field(
        default=None,
        max_length=255,
        description="Optional superadmin email address",
    )
    password: str = Field(
        ...,
        min_length=6,
        description="Superadmin account password",
    )


class BootstrapResponse(BaseModel):
    """Response returned upon successful system bootstrapping."""

    user: UserMeResponse
    tokens: TokenResponse


class ForgotPasswordRequest(BaseModel):
    """Payload to initiate a password reset OTP dispatch."""

    email: str = Field(
        ...,
        min_length=3,
        max_length=255,
        description="Registered staff email address",
        examples=["staff@munallab.com"],
    )

    @field_validator("email")
    @classmethod
    def validate_email_format(cls, v: str) -> str:
        v = v.strip().lower()
        if "@" not in v or "." not in v.split("@")[-1]:
            raise ValueError("Invalid email address format.")
        return v


class ResetPasswordRequest(BaseModel):
    """Payload to verify OTP and set a new password."""

    email: str = Field(
        ...,
        min_length=3,
        max_length=255,
        description="Registered staff email address",
        examples=["staff@munallab.com"],
    )
    otp: str = Field(
        ...,
        min_length=6,
        max_length=6,
        pattern=r"^\d{6}$",
        description="6-digit numeric verification passcode",
        examples=["481920"],
    )
    new_password: str = Field(
        ...,
        min_length=8,
        description="New secure password meeting complexity criteria",
        examples=["NewSecurePassword123!"],
    )

    @field_validator("email")
    @classmethod
    def validate_email_format(cls, v: str) -> str:
        v = v.strip().lower()
        if "@" not in v or "." not in v.split("@")[-1]:
            raise ValueError("Invalid email address format.")
        return v


class ForgotPasswordResponse(BaseModel):
    """Response when a password reset OTP was successfully dispatched."""

    message: str
    sent: bool = True


class MessageResponse(BaseModel):
    """Generic status message response."""

    message: str
