from datetime import datetime
from typing import List, Optional, Literal

from pydantic import BaseModel, Field


ShipmentStatus = Literal[
    "draft",
    "submitted",
    "booked",
    "in_transit",
    "delivered",
    "cancelled",
    "failed",
]


class FedExAddress(BaseModel):
    recipient_name: str = Field(min_length=2, max_length=150)
    company_name: Optional[str] = Field(default=None, max_length=150)
    address_line1: str = Field(min_length=2, max_length=200)
    address_line2: Optional[str] = Field(default=None, max_length=200)
    postal_code: str = Field(min_length=2, max_length=20)
    city: str = Field(min_length=2, max_length=120)
    country_code: str = Field(min_length=2, max_length=2)
    phone: Optional[str] = Field(default=None, max_length=50)
    email: Optional[str] = Field(default=None, max_length=150)


class FedExPackageInput(BaseModel):
    weight_kg: float = Field(gt=0, le=2000)
    length_cm: float = Field(gt=0, le=400)
    width_cm: float = Field(gt=0, le=400)
    height_cm: float = Field(gt=0, le=400)
    description: str = Field(min_length=1, max_length=255)


class FedExBookingCreate(BaseModel):
    case_id: int = Field(gt=0)
    customer_id: Optional[int] = Field(default=None, gt=0)
    contact_id: Optional[int] = Field(default=None, gt=0)
    service_type: Literal["PRIORITY", "ECONOMY"] = "PRIORITY"
    pickup_window_start: datetime
    pickup_window_end: datetime
    address: FedExAddress
    packages: List[FedExPackageInput] = Field(min_length=1, max_length=30)


class FedExBookingSubmitResponse(BaseModel):
    booking_ref: str
    status: ShipmentStatus
    dry_run: bool
    tracking_number: Optional[str] = None
    tracking_url: Optional[str] = None
    label_url: Optional[str] = None
    total_amount: Optional[float] = None
    currency: Optional[str] = None


class FedExTrackingEvent(BaseModel):
    status: str
    event_timestamp: datetime
    description: Optional[str] = None
    location_city: Optional[str] = None
    location_country: Optional[str] = None


class FedExBookingResponse(BaseModel):
    id: int
    booking_ref: str
    case_id: int
    customer_id: Optional[int] = None
    contact_id: Optional[int] = None
    service_type: str
    shipment_status: ShipmentStatus
    recipient_name: str
    city: str
    country_code: str
    tracking_number: Optional[str] = None
    tracking_url: Optional[str] = None
    label_url: Optional[str] = None
    total_amount: Optional[float] = None
    currency: Optional[str] = None
    dry_run: bool
    pickup_window_start: datetime
    pickup_window_end: datetime
    submitted_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    packages: List[FedExPackageInput] = Field(default_factory=list)


class FedExBookingListResponse(BaseModel):
    items: List[FedExBookingResponse]


class FedExTrackingResponse(BaseModel):
    booking_ref: str
    shipment_status: ShipmentStatus
    tracking_number: Optional[str] = None
    events: List[FedExTrackingEvent] = Field(default_factory=list)


class FedExCancelRequest(BaseModel):
    reason: Optional[str] = Field(default=None, max_length=400)


class FedExCancelResponse(BaseModel):
    booking_ref: str
    status: ShipmentStatus
    cancelled: bool
