from pydantic import BaseModel, EmailStr, Field, field_validator, ConfigDict
from typing import Optional
from datetime import datetime, date
from enum import Enum
import re


class BookingStatus(str, Enum):
    CONFIRMED = "Confirmed"
    PENDING = "Pending"
    CANCELLED = "Cancelled"
    CHECKED_IN = "Checked In"
    BOARDED = "Boarded"


class PaymentStatus(str, Enum):
    PENDING = "Pending"
    COMPLETED = "Completed"
    REFUNDED = "Refunded"
    FAILED = "Failed"


# Passenger Schemas
class PassengerBase(BaseModel):
    first_name: str = Field(..., min_length=1, max_length=100)
    last_name: str = Field(..., min_length=1, max_length=100)
    email: EmailStr
    phone: str = Field(..., min_length=1, max_length=50)
    date_of_birth: date
    passport_number: Optional[str] = Field(None, max_length=50)
    nationality: str = Field(..., min_length=1, max_length=100)

    @field_validator("passport_number")
    @classmethod
    def validate_passport_number(cls, v: Optional[str]) -> Optional[str]:
        if v is not None:
            if not re.match(r'^[A-Za-z0-9]{6,12}$', v):
                raise ValueError("Passport number must be alphanumeric and 6-12 characters")
        return v


class PassengerCreate(PassengerBase):
    pass


class PassengerUpdate(BaseModel):
    first_name: Optional[str] = Field(None, min_length=1, max_length=100)
    last_name: Optional[str] = Field(None, min_length=1, max_length=100)
    email: Optional[EmailStr] = None
    phone: Optional[str] = Field(None, min_length=1, max_length=50)
    date_of_birth: Optional[date] = None
    passport_number: Optional[str] = Field(None, max_length=50)
    nationality: Optional[str] = Field(None, min_length=1, max_length=100)

    @field_validator("passport_number")
    @classmethod
    def validate_passport_number(cls, v: Optional[str]) -> Optional[str]:
        if v is not None:
            if not re.match(r'^[A-Za-z0-9]{6,12}$', v):
                raise ValueError("Passport number must be alphanumeric and 6-12 characters")
        return v


class PassengerResponse(PassengerBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Booking Schemas
class BookingBase(BaseModel):
    passenger_id: str
    flight_id: str
    seat_id: Optional[str] = None
    fare_class_id: str
    booking_status: BookingStatus
    total_price: str
    payment_status: PaymentStatus
    payment_method: Optional[str] = Field(None, max_length=100)
    booking_date: datetime
    special_requests: Optional[str] = None

    @field_validator("total_price")
    @classmethod
    def validate_total_price(cls, v: str) -> str:
        try:
            price = float(v)
            if price < 0:
                raise ValueError("Total price must be greater than or equal to 0")
        except ValueError as e:
            if "could not convert" in str(e):
                raise ValueError("Total price must be a valid number")
            raise
        return v


class BookingCreate(BookingBase):
    pass


class BookingUpdate(BaseModel):
    passenger_id: Optional[str] = None
    flight_id: Optional[str] = None
    seat_id: Optional[str] = None
    fare_class_id: Optional[str] = None
    booking_status: Optional[BookingStatus] = None
    total_price: Optional[str] = None
    payment_status: Optional[PaymentStatus] = None
    payment_method: Optional[str] = Field(None, max_length=100)
    booking_date: Optional[datetime] = None
    special_requests: Optional[str] = None

    @field_validator("total_price")
    @classmethod
    def validate_total_price(cls, v: Optional[str]) -> Optional[str]:
        if v is not None:
            try:
                price = float(v)
                if price < 0:
                    raise ValueError("Total price must be greater than or equal to 0")
            except ValueError as e:
                if "could not convert" in str(e):
                    raise ValueError("Total price must be a valid number")
                raise
        return v


class BookingResponse(BookingBase):
    id: str
    booking_reference: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Detail Response Schemas
class RouteAirportResponse(BaseModel):
    code: str
    name: str
    city: str

    model_config = ConfigDict(from_attributes=True)


class RouteDetailResponse(BaseModel):
    origin_airport: RouteAirportResponse
    destination_airport: RouteAirportResponse
    distance_km: int
    estimated_duration_minutes: int

    model_config = ConfigDict(from_attributes=True)


class AircraftDetailResponse(BaseModel):
    registration_number: str
    model: str

    model_config = ConfigDict(from_attributes=True)


class SeatDetailResponse(BaseModel):
    seat_number: str
    class_type: str

    model_config = ConfigDict(from_attributes=True)


class FareClassDetailResponse(BaseModel):
    name: str
    class_type: str

    model_config = ConfigDict(from_attributes=True)


class FlightDetailResponse(BaseModel):
    flight_number: str
    scheduled_departure: datetime
    scheduled_arrival: datetime
    status: str
    route: RouteDetailResponse
    aircraft: AircraftDetailResponse

    model_config = ConfigDict(from_attributes=True)


class BookingDetailResponse(BaseModel):
    id: str
    booking_reference: str
    booking_status: str
    total_price: str
    payment_status: str
    payment_method: Optional[str]
    booking_date: datetime
    special_requests: Optional[str]
    passenger: PassengerResponse
    flight: FlightDetailResponse
    seat: Optional[SeatDetailResponse]
    fare_class: FareClassDetailResponse
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class BookingListItemResponse(BaseModel):
    booking_reference: str
    booking_status: str
    total_price: str
    flight_number: str
    scheduled_departure: datetime
    origin_code: str
    destination_code: str

    model_config = ConfigDict(from_attributes=True)


class PassengerDetailResponse(BaseModel):
    id: str
    first_name: str
    last_name: str
    email: str
    phone: str
    date_of_birth: date
    passport_number: Optional[str]
    nationality: str
    bookings: list[BookingListItemResponse]
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)