"""Connection application schemas."""
from datetime import date

from pydantic import BaseModel, ConfigDict, Field, field_validator

from app.models.enums import ApplicationStatus, ConnectionType, DocumentType
from app.schemas.auth import UserBrief
from app.schemas.common import Message  # noqa: F401 - re-exported for router convenience
from app.schemas.reference import AreaWithZoneOut
from app.schemas.types import DhakaDateTime, TrimmedStr


def _digits(value: str) -> str:
    return "".join(c for c in value if c.isdigit())


class _PhoneMixin:
    @field_validator("phone", "alt_phone", check_fields=False)
    @classmethod
    def check_phone(cls, v: str | None) -> str | None:
        """Bangladesh mobile numbers: 11 digits starting 01, optionally +880-prefixed."""
        if v is None or not v.strip():
            return None
        digits = _digits(v)
        if digits.startswith("880"):
            digits = "0" + digits[3:]
        if len(digits) != 11 or not digits.startswith("01"):
            raise ValueError("phone must be a valid 11-digit BD mobile number (01XXXXXXXXX)")
        return digits


class ApplicationCreate(_PhoneMixin, BaseModel):
    applicant_name: TrimmedStr = Field(min_length=2, max_length=150)
    father_name: str | None = Field(None, max_length=150)
    phone: str = Field(max_length=20)
    alt_phone: str = Field(max_length=20)
    nid: str | None = Field(None, max_length=30)
    email: str | None = Field(None, max_length=255)
    address: TrimmedStr = Field(min_length=5)
    area_id: int
    requested_date: date
    connection_type: ConnectionType
    assigned_technician_id: int | None = None
    notes: str | None = None

    @field_validator("nid")
    @classmethod
    def check_nid(cls, v: str | None) -> str | None:
        """Bangladesh NIDs are 10, 13, or 17 digits."""
        if v is None or not v.strip():
            return None
        digits = _digits(v)
        if len(digits) not in (10, 13, 17):
            raise ValueError("NID must be 10, 13, or 17 digits")
        return digits


class ApplicationUpdate(_PhoneMixin, BaseModel):
    """PATCH semantics. Status is not editable here — use the status endpoint."""

    applicant_name: TrimmedStr | None = Field(None, min_length=2, max_length=150)
    father_name: str | None = Field(None, max_length=150)
    phone: str | None = Field(None, max_length=20)
    alt_phone: str | None = Field(None, max_length=20)
    nid: str | None = Field(None, max_length=30)
    email: str | None = Field(None, max_length=255)
    address: TrimmedStr | None = Field(None, min_length=5)
    area_id: int | None = None
    requested_date: date | None = None
    connection_type: ConnectionType | None = None
    assigned_technician_id: int | None = None
    survey_date: date | None = None
    notes: str | None = None


class ApplicationStatusChange(BaseModel):
    status: ApplicationStatus
    remarks: str | None = None
    #: Required when moving to `rejected`.
    rejection_reason: str | None = None
    #: Only meaningful when moving to `survey`.
    survey_date: date | None = None
    #: Only meaningful when moving to `installed` — defaults to today (Dhaka).
    activated_on: date | None = None
    monthly_bill: float | None = None


class StatusHistoryOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    from_status: ApplicationStatus | None
    to_status: ApplicationStatus
    changed_at: DhakaDateTime
    remarks: str | None
    changed_by: UserBrief | None


class DocumentOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    doc_type: DocumentType
    file_name: str
    content_type: str | None
    file_size: int
    created_at: DhakaDateTime
    uploaded_by: UserBrief | None


class ApplicationListItem(BaseModel):
    """Row shape for the list view — flat enough to render a table directly."""

    model_config = ConfigDict(from_attributes=True)

    id: int
    application_no: str
    applicant_name: str
    father_name: str | None
    phone: str
    address: str
    status: ApplicationStatus
    requested_date: date
    connection_type: ConnectionType
    area: AreaWithZoneOut
    technician: UserBrief | None
    created_at: DhakaDateTime


class ApplicationDetail(ApplicationListItem):
    alt_phone: str | None
    nid: str | None
    email: str | None
    notes: str | None
    survey_date: date | None
    surveyed_at: DhakaDateTime | None
    approved_at: DhakaDateTime | None
    installed_at: DhakaDateTime | None
    rejected_at: DhakaDateTime | None
    rejection_reason: str | None
    created_by: UserBrief | None
    updated_at: DhakaDateTime
    status_history: list[StatusHistoryOut]
    documents: list[DocumentOut]
    #: Statuses this application may move to next, so the UI can build its buttons.
    allowed_transitions: list[ApplicationStatus] = []


class ApplicationStatusCount(BaseModel):
    status: ApplicationStatus
    count: int
