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


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


class PaymentStatus(str, Enum):
    PENDING = "pending"
    COMPLETED = "completed"
    FAILED = "failed"
    REFUNDED = "refunded"


class TicketValidityStatus(str, Enum):
    VALID = "valid"
    USED = "used"
    CANCELLED = "cancelled"


class BookingBase(BaseModel):
    reservation_id: str
    user_id: str
    schedule_id: str
    booking_datetime: datetime
    total_amount: Decimal
    payment_status: PaymentStatus
    booking_reference: str
    status: BookingStatus

    @field_validator("booking_reference")
    @classmethod
    def validate_booking_reference(cls, v: str) -> str:
        if not v:
            raise ValueError("Booking reference is required")
        if not (8 <= len(v) <= 12):
            raise ValueError("Booking reference must be 8-12 characters")
        if not v.isalnum():
            raise ValueError("Booking reference must be alphanumeric")
        return v

    @field_validator("total_amount")
    @classmethod
    def validate_total_amount(cls, v: Decimal) -> Decimal:
        if v <= 0:
            raise ValueError("Total amount must be positive")
        return v


class BookingCreate(BaseModel):
    reservation_id: str
    user_id: str
    schedule_id: str
    booking_datetime: datetime
    total_amount: Decimal
    payment_status: PaymentStatus
    booking_reference: str
    status: BookingStatus

    @field_validator("booking_reference")
    @classmethod
    def validate_booking_reference(cls, v: str) -> str:
        if not v:
            raise ValueError("Booking reference is required")
        if not (8 <= len(v) <= 12):
            raise ValueError("Booking reference must be 8-12 characters")
        if not v.isalnum():
            raise ValueError("Booking reference must be alphanumeric")
        return v

    @field_validator("total_amount")
    @classmethod
    def validate_total_amount(cls, v: Decimal) -> Decimal:
        if v <= 0:
            raise ValueError("Total amount must be positive")
        return v


class BookingUpdate(BaseModel):
    reservation_id: Optional[str] = None
    user_id: Optional[str] = None
    schedule_id: Optional[str] = None
    booking_datetime: Optional[datetime] = None
    total_amount: Optional[Decimal] = None
    payment_status: Optional[PaymentStatus] = None
    booking_reference: Optional[str] = None
    status: Optional[BookingStatus] = None

    @field_validator("booking_reference")
    @classmethod
    def validate_booking_reference(cls, v: Optional[str]) -> Optional[str]:
        if v is not None:
            if not v:
                raise ValueError("Booking reference cannot be empty")
            if not (8 <= len(v) <= 12):
                raise ValueError("Booking reference must be 8-12 characters")
            if not v.isalnum():
                raise ValueError("Booking reference must be alphanumeric")
        return v

    @field_validator("total_amount")
    @classmethod
    def validate_total_amount(cls, v: Optional[Decimal]) -> Optional[Decimal]:
        if v is not None and v <= 0:
            raise ValueError("Total amount must be positive")
        return v


class BookingResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    reservation_id: str
    user_id: str
    schedule_id: str
    booking_datetime: datetime
    total_amount: Decimal
    payment_status: PaymentStatus
    booking_reference: str
    status: BookingStatus
    created_at: datetime
    updated_at: datetime


class BookingseatBase(BaseModel):
    booking_id: str
    seat_id: str
    seat_number: str


class BookingseatCreate(BaseModel):
    booking_id: str
    seat_id: str
    seat_number: str


class BookingseatUpdate(BaseModel):
    booking_id: Optional[str] = None
    seat_id: Optional[str] = None
    seat_number: Optional[str] = None


class BookingseatResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    booking_id: str
    seat_id: str
    seat_number: str
    created_at: datetime
    updated_at: datetime


class TicketBase(BaseModel):
    booking_id: str
    ticket_number: str
    qr_code: str
    issue_datetime: datetime
    validity_status: TicketValidityStatus


class TicketCreate(BaseModel):
    booking_id: str
    ticket_number: str
    qr_code: str
    issue_datetime: datetime
    validity_status: TicketValidityStatus


class TicketUpdate(BaseModel):
    booking_id: Optional[str] = None
    ticket_number: Optional[str] = None
    qr_code: Optional[str] = None
    issue_datetime: Optional[datetime] = None
    validity_status: Optional[TicketValidityStatus] = None


class TicketResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    booking_id: str
    ticket_number: str
    qr_code: str
    issue_datetime: datetime
    validity_status: TicketValidityStatus
    created_at: datetime
    updated_at: datetime


class UserSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    email: str
    first_name: str
    last_name: str
    phone_number: str


class BusSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    bus_number: str
    bus_type: str


class RouteSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    origin_city: str
    destination_city: str


class ScheduleSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    departure_datetime: datetime
    arrival_datetime: datetime
    bus: BusSummary
    route: RouteSummary


class SeatSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    seat_type: str


class BookingSeatDetail(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    seat_number: str
    seat: SeatSummary


class PaymentSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    amount: Decimal
    payment_method: str
    status: str


class TicketSummary(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    ticket_number: str
    qr_code: str
    validity_status: str


class BookingDetailResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    reservation_id: str
    booking_datetime: datetime
    total_amount: Decimal
    payment_status: PaymentStatus
    booking_reference: str
    status: BookingStatus
    created_at: datetime
    updated_at: datetime
    user: UserSummary
    schedule: ScheduleSummary
    booking_seats: List[BookingSeatDetail]
    ticket: Optional[TicketSummary]
    payments: List[PaymentSummary]