from datetime import date, datetime
from decimal import Decimal

from pydantic import BaseModel, ConfigDict, Field


class ServiceRequestBase(BaseModel):
    reference: str | None = Field(None, max_length=40)
    account_id: int | None = None
    contact_id: int | None = None
    opportunity_id: int | None = None
    operation_type: str = Field(..., max_length=20)  # importacion | exportacion
    transport_mode: str | None = Field(None, max_length=20)
    service_type: str | None = Field(None, max_length=20)
    incoterm: str | None = Field(None, max_length=10)
    # Ruta legada (texto libre) — se conserva por compatibilidad
    origin: str | None = Field(None, max_length=160)
    destination: str | None = Field(None, max_length=160)
    # Ruta estructurada (país por catálogo ISO; ciudad/puerto por catálogo o texto)
    origin_country: str | None = Field(None, max_length=3)
    origin_city: str | None = Field(None, max_length=120)
    origin_port: str | None = Field(None, max_length=20)
    destination_country: str | None = Field(None, max_length=3)
    destination_city: str | None = Field(None, max_length=120)
    destination_port: str | None = Field(None, max_length=20)
    pickup_location: str | None = Field(None, max_length=255)
    delivery_location: str | None = Field(None, max_length=255)
    cargo_type: str | None = Field(None, max_length=120)
    weight: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)  # peso bruto
    volume: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    load_type: str | None = Field(None, max_length=10)  # FCL | LCL | AMBAS
    container_equipment: str | None = Field(None, max_length=120)
    container_count: int | None = Field(None, ge=0)
    commodity: str | None = None
    required_date: date | None = None
    request_date: date | None = None
    estimated_shipment_date: date | None = None
    currency: str | None = Field(None, max_length=3)
    priority: str | None = Field(None, max_length=20)
    # Mercancía
    cargo_value: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=2)
    insurance_required: bool = False
    hs_code: str | None = Field(None, max_length=20)
    goods_origin_country: str | None = Field(None, max_length=3)
    hazardous_imo: bool = False
    refrigerated: bool = False
    stackable: bool = False
    # Dimensiones y bultos
    pieces_count: int | None = Field(None, ge=0)
    boxes_count: int | None = Field(None, ge=0)
    pallets_count: int | None = Field(None, ge=0)
    net_weight: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    length_cm: Decimal | None = Field(None, ge=0, max_digits=10, decimal_places=2)
    width_cm: Decimal | None = Field(None, ge=0, max_digits=10, decimal_places=2)
    height_cm: Decimal | None = Field(None, ge=0, max_digits=10, decimal_places=2)
    measurement_unit: str | None = Field(None, max_length=20)
    # LCL
    packaging_type: str | None = Field(None, max_length=20)
    oversized: bool = False
    weight_per_pallet: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    volume_per_pallet: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    # Servicios adicionales (códigos del catálogo servicio_adicional) y pago
    additional_services: list[str] | None = None
    additional_service_costs: dict[str, float] | None = None  # {codigo: costo estimado}
    payment_method: str | None = Field(None, max_length=20)
    destination_agent_id: int | None = None
    requirements: str | None = None
    client_notes: str | None = None
    internal_notes: str | None = None
    status: str = Field("nueva", max_length=20)
    notes: str | None = None
    owner_user_id: str | None = Field(None, max_length=64)


class ServiceRequestCreate(ServiceRequestBase):
    pass


class ServiceRequestContactInput(BaseModel):
    """Registro del contacto al cliente como etapa del flujo comercial (R-C-04)."""
    notes: str | None = None


class ServiceRequestFromOpportunityInput(BaseModel):
    """Datos para convertir una oportunidad del embudo en solicitud/RFQ (R-C-02).

    La dirección impo/expo se hereda de la oportunidad; ``operation_type`` aquí es
    solo un respaldo para oportunidades antiguas que no la tengan capturada.
    """
    operation_type: str | None = Field(None, max_length=20)  # importacion | exportacion
    transport_mode: str | None = Field(None, max_length=20)
    service_type: str | None = Field(None, max_length=20)
    incoterm: str | None = Field(None, max_length=10)
    origin: str | None = Field(None, max_length=160)
    destination: str | None = Field(None, max_length=160)
    notes: str | None = None


class ServiceRequestUpdate(BaseModel):
    reference: str | None = Field(None, max_length=40)
    account_id: int | None = None
    contact_id: int | None = None
    opportunity_id: int | None = None
    operation_type: str | None = Field(None, max_length=20)
    transport_mode: str | None = Field(None, max_length=20)
    service_type: str | None = Field(None, max_length=20)
    incoterm: str | None = Field(None, max_length=10)
    origin: str | None = Field(None, max_length=160)
    destination: str | None = Field(None, max_length=160)
    origin_country: str | None = Field(None, max_length=3)
    origin_city: str | None = Field(None, max_length=120)
    origin_port: str | None = Field(None, max_length=20)
    destination_country: str | None = Field(None, max_length=3)
    destination_city: str | None = Field(None, max_length=120)
    destination_port: str | None = Field(None, max_length=20)
    pickup_location: str | None = Field(None, max_length=255)
    delivery_location: str | None = Field(None, max_length=255)
    cargo_type: str | None = Field(None, max_length=120)
    weight: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    volume: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    load_type: str | None = Field(None, max_length=10)
    container_equipment: str | None = Field(None, max_length=120)
    container_count: int | None = Field(None, ge=0)
    commodity: str | None = None
    required_date: date | None = None
    request_date: date | None = None
    estimated_shipment_date: date | None = None
    currency: str | None = Field(None, max_length=3)
    priority: str | None = Field(None, max_length=20)
    cargo_value: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=2)
    insurance_required: bool | None = None
    hs_code: str | None = Field(None, max_length=20)
    goods_origin_country: str | None = Field(None, max_length=3)
    hazardous_imo: bool | None = None
    refrigerated: bool | None = None
    stackable: bool | None = None
    pieces_count: int | None = Field(None, ge=0)
    boxes_count: int | None = Field(None, ge=0)
    pallets_count: int | None = Field(None, ge=0)
    net_weight: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    length_cm: Decimal | None = Field(None, ge=0, max_digits=10, decimal_places=2)
    width_cm: Decimal | None = Field(None, ge=0, max_digits=10, decimal_places=2)
    height_cm: Decimal | None = Field(None, ge=0, max_digits=10, decimal_places=2)
    measurement_unit: str | None = Field(None, max_length=20)
    packaging_type: str | None = Field(None, max_length=20)
    oversized: bool | None = None
    weight_per_pallet: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    volume_per_pallet: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=3)
    additional_services: list[str] | None = None
    additional_service_costs: dict[str, float] | None = None
    payment_method: str | None = Field(None, max_length=20)
    destination_agent_id: int | None = None
    requirements: str | None = None
    client_notes: str | None = None
    internal_notes: str | None = None
    status: str | None = Field(None, max_length=20)
    notes: str | None = None
    owner_user_id: str | None = Field(None, max_length=64)


class ServiceRequestResponse(ServiceRequestBase):
    model_config = ConfigDict(from_attributes=True)

    id: int
    case_id: int | None = None
    first_contact_at: datetime | None = None
    first_contact_notes: str | None = None
    tenant_id: int
    company_id: int
    created_by: str | None = None
    updated_by: str | None = None
    created_at: datetime
    updated_at: datetime


class RateRequestBase(BaseModel):
    service_request_id: int
    supplier_id: int | None = None
    concept: str = Field(..., max_length=60)
    description: str | None = Field(None, max_length=255)
    status: str = Field("solicitada", max_length=20)
    rate_amount: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=2)
    currency: str | None = Field(None, max_length=3)
    valid_until: date | None = None
    notes: str | None = None


class RateRequestCreate(RateRequestBase):
    pass


class RateRequestUpdate(BaseModel):
    supplier_id: int | None = None
    concept: str | None = Field(None, max_length=60)
    description: str | None = Field(None, max_length=255)
    status: str | None = Field(None, max_length=20)
    rate_amount: Decimal | None = Field(None, ge=0, max_digits=14, decimal_places=2)
    currency: str | None = Field(None, max_length=3)
    valid_until: date | None = None
    notes: str | None = None


class RateRequestResponse(RateRequestBase):
    model_config = ConfigDict(from_attributes=True)

    id: int
    tenant_id: int
    company_id: int
    created_at: datetime
    updated_at: datetime
