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


class ReservationStatus(str, Enum):
    ACTIVE = "active"
    EXPIRED = "expired"
    CONFIRMED = "confirmed"
    CANCELLED = "cancelled"


class ReservationseatBase(BaseModel):
    reservation_id: str
    seat_id: str


class ReservationseatCreate(ReservationseatBase):
    pass


class ReservationseatUpdate(BaseModel):
    reservation_id: Optional[str] = None
    seat_id: Optional[str] = None


class ReservationseatResponse(ReservationseatBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class ReservationBase(BaseModel):
    user_id: str
    schedule_id: str
    reservation_datetime: datetime
    expiry_datetime: datetime
    status: ReservationStatus
    total_amount: float

    @field_validator("total_amount")
    @classmethod
    def validate_total_amount(cls, v: float) -> float:
        if v < 0:
            raise ValueError("total_amount must be a positive number")
        return v

    @field_validator("expiry_datetime")
    @classmethod
    def validate_expiry_datetime(cls, v: datetime, info) -> datetime:
        reservation_datetime = info.data.get("reservation_datetime")
        if reservation_datetime and v <= reservation_datetime:
            raise ValueError("expiry_datetime must be after reservation_datetime")
        return v


class ReservationCreate(ReservationBase):
    seat_ids: List[str]

    @field_validator("seat_ids")
    @classmethod
    def validate_seat_ids(cls, v: List[str]) -> List[str]:
        if not v:
            raise ValueError("At least one seat must be selected")
        if len(v) > 6:
            raise ValueError("Maximum 6 seats can be reserved per transaction")
        if len(v) != len(set(v)):
            raise ValueError("Duplicate seat IDs are not allowed")
        return v


class ReservationUpdate(BaseModel):
    user_id: Optional[str] = None
    schedule_id: Optional[str] = None
    reservation_datetime: Optional[datetime] = None
    expiry_datetime: Optional[datetime] = None
    status: Optional[ReservationStatus] = None
    total_amount: Optional[float] = None

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


class ReservationResponse(ReservationBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class SeatDetailResponse(BaseModel):
    id: str
    seat_number: str
    seat_type: str
    price_modifier: float

    model_config = ConfigDict(from_attributes=True)


class UserDetailResponse(BaseModel):
    id: str
    email: str
    first_name: str
    last_name: str

    model_config = ConfigDict(from_attributes=True)


class BusDetailResponse(BaseModel):
    id: str
    bus_number: str

    model_config = ConfigDict(from_attributes=True)


class RouteDetailResponse(BaseModel):
    id: str
    origin_city: str
    destination_city: str

    model_config = ConfigDict(from_attributes=True)


class ScheduleDetailResponse(BaseModel):
    id: str
    departure_datetime: datetime
    arrival_datetime: datetime
    bus: BusDetailResponse
    route: RouteDetailResponse

    model_config = ConfigDict(from_attributes=True)


class ReservationSeatDetailResponse(BaseModel):
    seat: SeatDetailResponse

    model_config = ConfigDict(from_attributes=True)


class ReservationDetailResponse(BaseModel):
    id: str
    user_id: str
    schedule_id: str
    reservation_datetime: datetime
    expiry_datetime: datetime
    status: ReservationStatus
    total_amount: float
    created_at: datetime
    updated_at: datetime
    user: UserDetailResponse
    schedule: ScheduleDetailResponse
    reservation_seats: List[ReservationSeatDetailResponse]

    model_config = ConfigDict(from_attributes=True)