from pydantic import BaseModel, Field, field_validator, ConfigDict
from typing import Optional, List
from datetime import datetime, date
from decimal import Decimal
from enum import Enum


class FlightStatus(str, Enum):
    SCHEDULED = "Scheduled"
    BOARDING = "Boarding"
    DEPARTED = "Departed"
    ARRIVED = "Arrived"
    CANCELLED = "Cancelled"
    DELAYED = "Delayed"


class FareClassType(str, Enum):
    ECONOMY = "Economy"
    PREMIUM_ECONOMY = "Premium Economy"
    BUSINESS = "Business"
    FIRST_CLASS = "First Class"


# Fareclass schemas
class FareclassBase(BaseModel):
    name: str = Field(..., max_length=100)
    class_type: str = Field(..., max_length=50)
    price_multiplier: Decimal = Field(..., gt=0)
    baggage_allowance_kg: Decimal = Field(..., ge=0)
    cancellation_allowed: str = Field(..., max_length=10)
    change_fee_percentage: Decimal = Field(..., ge=0, le=100)

    @field_validator("price_multiplier")
    @classmethod
    def validate_price_multiplier(cls, v: Decimal) -> Decimal:
        if v <= 0:
            raise ValueError("FareClass price_multiplier must be greater than 0")
        return v

    @field_validator("baggage_allowance_kg")
    @classmethod
    def validate_baggage_allowance(cls, v: Decimal) -> Decimal:
        if v < 0:
            raise ValueError("FareClass baggage_allowance_kg must be greater than or equal to 0")
        return v

    @field_validator("change_fee_percentage")
    @classmethod
    def validate_change_fee_percentage(cls, v: Decimal) -> Decimal:
        if v < 0 or v > 100:
            raise ValueError("FareClass change_fee_percentage must be between 0 and 100")
        return v


class FareclassCreate(FareclassBase):
    pass


class FareclassUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=100)
    class_type: Optional[str] = Field(None, max_length=50)
    price_multiplier: Optional[Decimal] = Field(None, gt=0)
    baggage_allowance_kg: Optional[Decimal] = Field(None, ge=0)
    cancellation_allowed: Optional[str] = Field(None, max_length=10)
    change_fee_percentage: Optional[Decimal] = Field(None, ge=0, le=100)

    @field_validator("price_multiplier")
    @classmethod
    def validate_price_multiplier(cls, v: Optional[Decimal]) -> Optional[Decimal]:
        if v is not None and v <= 0:
            raise ValueError("FareClass price_multiplier must be greater than 0")
        return v

    @field_validator("baggage_allowance_kg")
    @classmethod
    def validate_baggage_allowance(cls, v: Optional[Decimal]) -> Optional[Decimal]:
        if v is not None and v < 0:
            raise ValueError("FareClass baggage_allowance_kg must be greater than or equal to 0")
        return v

    @field_validator("change_fee_percentage")
    @classmethod
    def validate_change_fee_percentage(cls, v: Optional[Decimal]) -> Optional[Decimal]:
        if v is not None and (v < 0 or v > 100):
            raise ValueError("FareClass change_fee_percentage must be between 0 and 100")
        return v


class FareclassResponse(FareclassBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Flight schemas
class FlightBase(BaseModel):
    flight_number: str = Field(..., max_length=50)
    route_id: str = Field(..., max_length=36)
    aircraft_id: str = Field(..., max_length=36)
    scheduled_departure: datetime
    scheduled_arrival: datetime
    actual_departure: Optional[datetime] = None
    actual_arrival: Optional[datetime] = None
    base_fare: Decimal = Field(..., gt=0)
    status: str = Field(default="Scheduled", max_length=50)
    gate: Optional[str] = Field(None, max_length=20)

    @field_validator("base_fare")
    @classmethod
    def validate_base_fare(cls, v: Decimal) -> Decimal:
        if v <= 0:
            raise ValueError("Flight base_fare must be greater than 0")
        return v


class FlightCreate(FlightBase):
    pass


class FlightUpdate(BaseModel):
    flight_number: Optional[str] = Field(None, max_length=50)
    route_id: Optional[str] = Field(None, max_length=36)
    aircraft_id: Optional[str] = Field(None, max_length=36)
    scheduled_departure: Optional[datetime] = None
    scheduled_arrival: Optional[datetime] = None
    actual_departure: Optional[datetime] = None
    actual_arrival: Optional[datetime] = None
    base_fare: Optional[Decimal] = Field(None, gt=0)
    status: Optional[str] = Field(None, max_length=50)
    gate: Optional[str] = Field(None, max_length=20)

    @field_validator("base_fare")
    @classmethod
    def validate_base_fare(cls, v: Optional[Decimal]) -> Optional[Decimal]:
        if v is not None and v <= 0:
            raise ValueError("Flight base_fare must be greater than 0")
        return v


class FlightResponse(FlightBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Detail response schemas
class AirportDetailResponse(BaseModel):
    code: str
    name: str
    city: str

    model_config = ConfigDict(from_attributes=True)


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

    model_config = ConfigDict(from_attributes=True)


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

    model_config = ConfigDict(from_attributes=True)


class BookingDetailResponse(BaseModel):
    booking_reference: str
    booking_status: str

    model_config = ConfigDict(from_attributes=True)


class CrewMemberDetailResponse(BaseModel):
    first_name: str
    last_name: str

    model_config = ConfigDict(from_attributes=True)


class FlightCrewAssignmentDetailResponse(BaseModel):
    assigned_role: str
    crew_member: CrewMemberDetailResponse

    model_config = ConfigDict(from_attributes=True)


class FlightDetailResponse(BaseModel):
    id: str
    flight_number: str
    scheduled_departure: datetime
    scheduled_arrival: datetime
    actual_departure: Optional[datetime]
    actual_arrival: Optional[datetime]
    base_fare: Decimal
    status: str
    gate: Optional[str]
    route: RouteDetailResponse
    aircraft: AircraftDetailResponse
    bookings: List[BookingDetailResponse]
    flight_crew_assignments: List[FlightCrewAssignmentDetailResponse]
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class FlightSearchRequest(BaseModel):
    origin: str = Field(..., max_length=3)
    destination: str = Field(..., max_length=3)
    date: date


class FlightStatusUpdateRequest(BaseModel):
    status: FlightStatus


class PassengerManifestResponse(BaseModel):
    booking_reference: str
    passenger_first_name: str
    passenger_last_name: str
    seat_number: Optional[str]
    booking_status: str
    fare_class_name: str