from datetime import date, datetime, time

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

from app.models.reservation import ReservationSource, ReservationStatus
from app.schemas.customer import CustomerRead
from app.schemas.table import TableCombinationRead, TableRead
from app.services.contact_validation import normalize_customer_phone, normalize_optional_customer_email


class ReservationStatusHistoryRead(BaseModel):
    id: int
    reservation_id: int
    old_status: ReservationStatus | None
    new_status: ReservationStatus
    changed_at: datetime

    model_config = ConfigDict(from_attributes=True)


class ReservationBase(BaseModel):
    venue_id: int
    reservation_date: date
    start_time: time
    duration_minutes: int = Field(gt=0, le=600)
    guests: int = Field(gt=0, le=120)
    status: ReservationStatus = ReservationStatus.pending
    source: ReservationSource = ReservationSource.manual
    notes: str | None = None
    area_preference: str | None = Field(default=None, max_length=120)


class ReservationCreate(ReservationBase):
    customer_id: int | None = None
    customer_name: str | None = Field(default=None, min_length=1, max_length=120)
    customer_phone: str | None = Field(default=None, min_length=3, max_length=40)
    customer_email: str | None = None
    customer_notes: str | None = None

    @model_validator(mode="after")
    def validate_customer_input(self) -> "ReservationCreate":
        if self.customer_id is None and (not self.customer_name or not self.customer_phone):
            raise ValueError("È richiesto customer_id oppure nome e telefono del cliente")
        return self

    @field_validator("customer_phone")
    @classmethod
    def validate_customer_phone(cls, value: str | None) -> str | None:
        if value is None:
            return None
        return normalize_customer_phone(value)

    @field_validator("customer_email")
    @classmethod
    def validate_customer_email(cls, value: str | None) -> str | None:
        return normalize_optional_customer_email(value)


class ReservationUpdate(BaseModel):
    customer_id: int | None = None
    customer_name: str | None = Field(default=None, min_length=1, max_length=120)
    customer_phone: str | None = Field(default=None, min_length=3, max_length=40)
    customer_email: str | None = None
    customer_notes: str | None = None
    reservation_date: date | None = None
    start_time: time | None = None
    duration_minutes: int | None = Field(default=None, gt=0, le=600)
    guests: int | None = Field(default=None, gt=0, le=120)
    status: ReservationStatus | None = None
    source: ReservationSource | None = None
    notes: str | None = None
    area_preference: str | None = Field(default=None, max_length=120)

    @field_validator("customer_phone")
    @classmethod
    def validate_customer_phone(cls, value: str | None) -> str | None:
        if value is None:
            return None
        return normalize_customer_phone(value)

    @field_validator("customer_email")
    @classmethod
    def validate_customer_email(cls, value: str | None) -> str | None:
        return normalize_optional_customer_email(value)


class ReservationRead(BaseModel):
    id: int
    venue_id: int
    customer_id: int
    reservation_date: date
    start_time: time
    duration_minutes: int
    guests: int
    status: ReservationStatus
    source: ReservationSource
    notes: str | None
    area_preference: str | None
    assigned_table_id: int | None
    assigned_combination_id: int | None
    created_at: datetime
    updated_at: datetime
    customer: CustomerRead
    assigned_table: TableRead | None = None
    assigned_combination: TableCombinationRead | None = None
    requires_table_join: bool = False
    service_summary: str | None = None
    service_steps: list[str] = []
    status_history: list[ReservationStatusHistoryRead] = []

    model_config = ConfigDict(from_attributes=True)


class RecalculateDayRequest(BaseModel):
    reservation_date: date


class AssignmentResult(BaseModel):
    reservation_id: int
    assigned_table_id: int | None
    assigned_combination_id: int | None
    assignment_label: str | None
    requires_table_join: bool = False
    service_summary: str | None = None
    service_steps: list[str] = []


class ReservationListResponse(BaseModel):
    items: list[ReservationRead]
    total: int
