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


class BookingStatus(str, Enum):
    PENDING = "pending"
    CONFIRMED = "confirmed"
    CANCELLED = "cancelled"
    COMPLETED = "completed"
    REFUNDED = "refunded"


class PaymentStatus(str, Enum):
    UNPAID = "unpaid"
    PARTIAL = "partial"
    PAID = "paid"
    REFUNDED = "refunded"


class TravelerType(str, Enum):
    ADULT = "adult"
    CHILD = "child"
    INFANT = "infant"


class Gender(str, Enum):
    MALE = "male"
    FEMALE = "female"
    OTHER = "other"


class TourScheduleStatus(str, Enum):
    SCHEDULED = "scheduled"
    CONFIRMED = "confirmed"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    CANCELLED = "cancelled"


class ResourceBookingStatus(str, Enum):
    PENDING = "pending"
    CONFIRMED = "confirmed"
    CANCELLED = "cancelled"


# Booking schemas
class BookingBase(BaseModel):
    customer_id: str
    tour_schedule_id: str
    booking_agent_id: Optional[str] = None
    discount_id: Optional[str] = None
    number_of_adults: int = 0
    number_of_children: int = 0
    number_of_infants: int = 0
    subtotal: float = 0.0
    discount_amount: float = 0.0
    tax_amount: float = 0.0
    total_amount: float = 0.0
    amount_paid: float = 0.0
    amount_due: float = 0.0
    booking_status: str = "pending"
    payment_status: str = "unpaid"
    special_requests: Optional[str] = None

    @field_validator("number_of_adults", "number_of_children", "number_of_infants")
    @classmethod
    def validate_traveler_counts(cls, v):
        if v < 0:
            raise ValueError("Traveler counts must be non-negative")
        return v

    @field_validator("subtotal", "discount_amount", "tax_amount", "total_amount", "amount_paid", "amount_due")
    @classmethod
    def validate_amounts(cls, v):
        if v < 0:
            raise ValueError("Amounts must be non-negative")
        return v


class BookingCreate(BookingBase):
    booking_number: str

    @field_validator("booking_number")
    @classmethod
    def validate_booking_number(cls, v):
        if not v or len(v.strip()) == 0:
            raise ValueError("Booking number is required")
        return v


class BookingUpdate(BaseModel):
    booking_agent_id: Optional[str] = None
    discount_id: Optional[str] = None
    number_of_adults: Optional[int] = None
    number_of_children: Optional[int] = None
    number_of_infants: Optional[int] = None
    subtotal: Optional[float] = None
    discount_amount: Optional[float] = None
    tax_amount: Optional[float] = None
    total_amount: Optional[float] = None
    amount_paid: Optional[float] = None
    amount_due: Optional[float] = None
    booking_status: Optional[str] = None
    payment_status: Optional[str] = None
    special_requests: Optional[str] = None
    cancellation_reason: Optional[str] = None
    cancelled_at: Optional[datetime] = None


class BookingResponse(BookingBase):
    id: str
    booking_number: str
    booking_date: datetime
    cancellation_reason: Optional[str] = None
    cancelled_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Traveler schemas
class TravelerBase(BaseModel):
    booking_id: str
    traveler_type: str
    first_name: str
    last_name: str
    date_of_birth: Optional[date] = None
    gender: Optional[str] = None
    nationality: Optional[str] = None
    passport_number: Optional[str] = None
    passport_expiry: Optional[date] = None
    special_requirements: Optional[str] = None
    meal_preference: Optional[str] = None
    is_primary: bool = False

    @field_validator("first_name", "last_name")
    @classmethod
    def validate_names(cls, v):
        if not v or len(v.strip()) == 0:
            raise ValueError("Name fields are required")
        return v


class TravelerCreate(TravelerBase):
    pass


class TravelerUpdate(BaseModel):
    traveler_type: Optional[str] = None
    first_name: Optional[str] = None
    last_name: Optional[str] = None
    date_of_birth: Optional[date] = None
    gender: Optional[str] = None
    nationality: Optional[str] = None
    passport_number: Optional[str] = None
    passport_expiry: Optional[date] = None
    special_requirements: Optional[str] = None
    meal_preference: Optional[str] = None
    is_primary: Optional[bool] = None


class TravelerResponse(TravelerBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Tourschedule schemas
class TourscheduleBase(BaseModel):
    tour_package_id: str
    tour_guide_id: Optional[str] = None
    departure_date: date
    return_date: date
    available_slots: int = 0
    booked_slots: int = 0
    status: str = "scheduled"
    meeting_point: Optional[str] = None
    meeting_time: Optional[time] = None
    special_instructions: Optional[str] = None

    @field_validator("available_slots", "booked_slots")
    @classmethod
    def validate_slots(cls, v):
        if v < 0:
            raise ValueError("Slots must be non-negative")
        return v

    @field_validator("return_date")
    @classmethod
    def validate_return_date(cls, v, info):
        if "departure_date" in info.data and v < info.data["departure_date"]:
            raise ValueError("Return date must be after departure date")
        return v


class TourscheduleCreate(TourscheduleBase):
    pass


class TourscheduleUpdate(BaseModel):
    tour_guide_id: Optional[str] = None
    departure_date: Optional[date] = None
    return_date: Optional[date] = None
    available_slots: Optional[int] = None
    booked_slots: Optional[int] = None
    status: Optional[str] = None
    meeting_point: Optional[str] = None
    meeting_time: Optional[time] = None
    special_instructions: Optional[str] = None


class TourscheduleResponse(TourscheduleBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Tourschedulehotel schemas
class TourschedulehotelBase(BaseModel):
    tour_schedule_id: str
    hotel_id: str
    room_type_id: Optional[str] = None
    check_in_date: date
    check_out_date: date
    rooms_booked: int = 0
    total_cost: float = 0.0
    booking_status: str = "pending"

    @field_validator("rooms_booked")
    @classmethod
    def validate_rooms(cls, v):
        if v < 0:
            raise ValueError("Rooms booked must be non-negative")
        return v

    @field_validator("total_cost")
    @classmethod
    def validate_cost(cls, v):
        if v < 0:
            raise ValueError("Total cost must be non-negative")
        return v

    @field_validator("check_out_date")
    @classmethod
    def validate_checkout_date(cls, v, info):
        if "check_in_date" in info.data and v < info.data["check_in_date"]:
            raise ValueError("Check-out date must be after check-in date")
        return v


class TourschedulehotelCreate(TourschedulehotelBase):
    pass


class TourschedulehotelUpdate(BaseModel):
    room_type_id: Optional[str] = None
    check_in_date: Optional[date] = None
    check_out_date: Optional[date] = None
    rooms_booked: Optional[int] = None
    total_cost: Optional[float] = None
    booking_status: Optional[str] = None


class TourschedulehotelResponse(TourschedulehotelBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Tourscheduletransportation schemas
class TourscheduletransportationBase(BaseModel):
    tour_schedule_id: str
    transportation_id: str
    departure_location: str
    arrival_location: str
    departure_datetime: datetime
    arrival_datetime: datetime
    seats_booked: int = 0
    total_cost: float = 0.0
    booking_status: str = "pending"

    @field_validator("seats_booked")
    @classmethod
    def validate_seats(cls, v):
        if v < 0:
            raise ValueError("Seats booked must be non-negative")
        return v

    @field_validator("total_cost")
    @classmethod
    def validate_cost(cls, v):
        if v < 0:
            raise ValueError("Total cost must be non-negative")
        return v

    @field_validator("arrival_datetime")
    @classmethod
    def validate_arrival_datetime(cls, v, info):
        if "departure_datetime" in info.data and v < info.data["departure_datetime"]:
            raise ValueError("Arrival datetime must be after departure datetime")
        return v

    @field_validator("departure_location", "arrival_location")
    @classmethod
    def validate_locations(cls, v):
        if not v or len(v.strip()) == 0:
            raise ValueError("Location fields are required")
        return v


class TourscheduletransportationCreate(TourscheduletransportationBase):
    pass


class TourscheduletransportationUpdate(BaseModel):
    departure_location: Optional[str] = None
    arrival_location: Optional[str] = None
    departure_datetime: Optional[datetime] = None
    arrival_datetime: Optional[datetime] = None
    seats_booked: Optional[int] = None
    total_cost: Optional[float] = None
    booking_status: Optional[str] = None


class TourscheduletransportationResponse(TourscheduletransportationBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


# Complex response schemas for detail endpoints
class CustomerUserResponse(BaseModel):
    first_name: str
    last_name: str
    email: str

    model_config = ConfigDict(from_attributes=True)


class CustomerDetailResponse(BaseModel):
    user: CustomerUserResponse

    model_config = ConfigDict(from_attributes=True)


class TourPackageResponse(BaseModel):
    name: str

    model_config = ConfigDict(from_attributes=True)


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

    model_config = ConfigDict(from_attributes=True)


class TourGuideDetailResponse(BaseModel):
    user: TourGuideUserResponse

    model_config = ConfigDict(from_attributes=True)


class TourScheduleDetailResponse(BaseModel):
    tour_package: TourPackageResponse
    tour_guide: Optional[TourGuideDetailResponse] = None

    model_config = ConfigDict(from_attributes=True)


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

    model_config = ConfigDict(from_attributes=True)


class DiscountResponse(BaseModel):
    code: str
    discount_value: float

    model_config = ConfigDict(from_attributes=True)


class InvoiceLineItemResponse(BaseModel):
    description: str
    quantity: int
    unit_price: float
    total_price: float

    model_config = ConfigDict(from_attributes=True)


class InvoiceDetailResponse(BaseModel):
    invoice_number: str
    invoice_line_items: List[InvoiceLineItemResponse]

    model_config = ConfigDict(from_attributes=True)


class PaymentDetailResponse(BaseModel):
    amount: float
    payment_status: str

    model_config = ConfigDict(from_attributes=True)


class BookingDetailResponse(BaseModel):
    id: str
    booking_number: str
    booking_date: datetime
    number_of_adults: int
    number_of_children: int
    number_of_infants: int
    subtotal: float
    discount_amount: float
    tax_amount: float
    total_amount: float
    amount_paid: float
    amount_due: float
    booking_status: str
    payment_status: str
    special_requests: Optional[str] = None
    customer: CustomerDetailResponse
    tour_schedule: TourScheduleDetailResponse
    booking_agent: Optional[BookingAgentResponse] = None
    discount: Optional[DiscountResponse] = None
    travelers: List[TravelerResponse]
    payments: List[PaymentDetailResponse]
    invoice: Optional[InvoiceDetailResponse] = None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class CategoryResponse(BaseModel):
    name: str

    model_config = ConfigDict(from_attributes=True)


class TourPackageDetailResponse(BaseModel):
    name: str
    category: CategoryResponse

    model_config = ConfigDict(from_attributes=True)


class HotelResponse(BaseModel):
    name: str

    model_config = ConfigDict(from_attributes=True)


class RoomTypeResponse(BaseModel):
    name: str

    model_config = ConfigDict(from_attributes=True)


class TourScheduleHotelDetailResponse(BaseModel):
    hotel: HotelResponse
    room_type: Optional[RoomTypeResponse] = None

    model_config = ConfigDict(from_attributes=True)


class TransportationResponse(BaseModel):
    vehicle_name: Optional[str] = None

    model_config = ConfigDict(from_attributes=True)


class TourScheduleTransportationDetailResponse(BaseModel):
    transportation: TransportationResponse

    model_config = ConfigDict(from_attributes=True)


class TourScheduleFullDetailResponse(BaseModel):
    id: str
    departure_date: date
    return_date: date
    available_slots: int
    booked_slots: int
    status: str
    meeting_point: Optional[str] = None
    meeting_time: Optional[time] = None
    special_instructions: Optional[str] = None
    tour_package: TourPackageDetailResponse
    tour_guide: Optional[TourGuideDetailResponse] = None
    tour_schedule_hotels: List[TourScheduleHotelDetailResponse]
    tour_schedule_transportations: List[TourScheduleTransportationDetailResponse]
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)