from datetime import datetime
from typing import Literal

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

RepairStatus = Literal[
    "new",
    "accepted",
    "diagnosis",
    "estimate",
    "waiting_for_customer",
    "approved",
    "repair",
    "final_test",
    "ready_for_pickup",
    "shipped",
    "completed",
    "cancelled",
]
RepairPriority = Literal["low", "normal", "high", "urgent"]
RepairSource = Literal["manual", "website", "customer_portal", "email", "phone"]


def normalize_text(value: object) -> str:
    if value is None:
        return ""
    return str(value).strip()


class RepairBase(BaseModel):
    customer_id: int | None = None
    contact_id: int | None = None
    status: RepairStatus = "new"
    priority: RepairPriority = "normal"
    source: RepairSource = "manual"
    source_reference: str | None = Field(default=None, max_length=120)
    customer_name: str = Field(default="", max_length=255)
    customer_email: EmailStr | None = None
    customer_phone: str = Field(default="", max_length=80)
    device_manufacturer: str = Field(min_length=1, max_length=160)
    device_model: str = Field(min_length=1, max_length=160)
    device_serial_number: str | None = Field(default=None, max_length=160)
    device_type: str = Field(default="", max_length=120)
    accessories: str = ""
    fault_description: str = Field(min_length=1)
    previous_work: str = ""
    device_opened: bool = False
    intake_notes: str = ""
    diagnosis_notes: str = ""
    repair_notes: str = ""
    estimate_notes: str = ""
    estimated_cost_cents: int | None = Field(default=None, ge=0)

    @field_validator(
        "source_reference",
        "customer_name",
        "customer_phone",
        "device_manufacturer",
        "device_model",
        "device_serial_number",
        "device_type",
        "accessories",
        "fault_description",
        "previous_work",
        "intake_notes",
        "diagnosis_notes",
        "repair_notes",
        "estimate_notes",
        mode="before",
    )
    @classmethod
    def normalize_strings(cls, value: object) -> str | None:
        if value is None:
            return None
        return normalize_text(value)

    @model_validator(mode="after")
    def validate_customer_identity(self):
        if self.customer_id is None and not self.customer_name:
            raise ValueError("Kundenname ist erforderlich, wenn kein Kunde ausgewählt ist")
        return self


class RepairCreate(RepairBase):
    pass


class RepairUpdate(RepairBase):
    pass


class RepairStatusUpdate(BaseModel):
    status: RepairStatus
    note: str | None = None

    @field_validator("note", mode="before")
    @classmethod
    def normalize_note(cls, value: object) -> str | None:
        if value is None:
            return None
        text = normalize_text(value)
        return text or None


class RepairResponse(RepairBase):
    id: int
    repair_number: str
    customer_email: str
    device_serial_number: str | None
    approved_at: datetime | None
    completed_at: datetime | None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class RepairListResponse(BaseModel):
    items: list[RepairResponse]
    total: int
    limit: int
    offset: int


class RepairStatusHistoryResponse(BaseModel):
    id: int
    repair_id: int
    old_status: str | None
    new_status: str
    note: str | None
    actor_user_id: int | None
    actor_username: str = ""
    actor_display_name: str = ""
    created_at: datetime

    model_config = ConfigDict(from_attributes=True)


class RepairIntakePayload(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    email: EmailStr | None = None
    phone: str = Field(default="", max_length=80)
    manufacturer: str = Field(min_length=1, max_length=160)
    model: str = Field(min_length=1, max_length=160)
    serial_number: str | None = Field(default=None, max_length=160)
    device_type: str = Field(default="", max_length=120)
    accessories: str = ""
    fault_description: str = Field(min_length=1)
    previous_work: str = ""
    device_opened: bool = False
    source_reference: str | None = Field(default=None, max_length=120)

    @field_validator("*", mode="before")
    @classmethod
    def normalize_payload(cls, value: object) -> object:
        if isinstance(value, str):
            return value.strip()
        return value


class RepairIntakeResponse(BaseModel):
    repair_number: str
    status: RepairStatus
    message: str


class RepairPublicLinkResponse(BaseModel):
    is_active: bool
    token_hint: str | None = None
    expires_at: datetime | None = None
    last_used_at: datetime | None = None
    created_at: datetime | None = None
    revoked_at: datetime | None = None
    public_status_path: str | None = None


class RepairPublicLinkCreateResponse(RepairPublicLinkResponse):
    token: str
    public_status_path: str


class RepairPublicStatusHistoryItem(BaseModel):
    status: RepairStatus
    status_label: str
    created_at: datetime


class RepairPublicStatusResponse(BaseModel):
    repair_number: str
    public_status_label: str
    device_manufacturer: str
    device_model: str
    status_history_public: list[RepairPublicStatusHistoryItem]
    updated_at: datetime


class RepairNotificationTemplateResponse(BaseModel):
    event_type: str
    status: RepairStatus | None = None
    subject: str
    text: str
    html: str | None = None


class RepairNotificationEventResponse(BaseModel):
    id: int
    repair_id: int
    event_type: str
    channel: str
    recipient: str
    subject: str
    template: str
    status: str
    success: bool
    error_message: str | None
    created_at: datetime
    sent_at: datetime | None

    model_config = ConfigDict(from_attributes=True)


class RepairNotificationOverviewResponse(BaseModel):
    templates: list[RepairNotificationTemplateResponse]
    events: list[RepairNotificationEventResponse]
