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


class ScheduleStatus(str, Enum):
    SCHEDULED = "scheduled"
    IN_TRANSIT = "in_transit"
    COMPLETED = "completed"
    CANCELLED = "cancelled"


class SeatType(str, Enum):
    STANDARD = "standard"
    PREMIUM = "premium"
    SLEEPER = "sleeper"


class SeatStatus(str, Enum):
    AVAILABLE = "available"
    RESERVED = "reserved"
    BOOKED = "booked"


class ScheduleBase(BaseModel):
    bus_id: str
    route_id: str
    departure_datetime: datetime
    arrival_datetime: datetime
    base_price: float
    available_seats: int
    status: ScheduleStatus

    @field_validator("base_price")
    @classmethod
    def validate_base_price(cls, v):
        if v <= 0:
            raise ValueError("Base price must be a positive number")
        return v

    @field_validator("available_seats")
    @classmethod
    def validate_available_seats(cls, v):
        if v < 0:
            raise ValueError("Available seats cannot be negative")
        return v

    @field_validator("arrival_datetime")
    @classmethod
    def validate_arrival_after_departure(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


class ScheduleCreate(ScheduleBase):
    pass


class ScheduleUpdate(BaseModel):
    bus_id: Optional[str] = None
    route_id: Optional[str] = None
    departure_datetime: Optional[datetime] = None
    arrival_datetime: Optional[datetime] = None
    base_price: Optional[float] = None
    available_seats: Optional[int] = None
    status: Optional[ScheduleStatus] = None

    @field_validator("base_price")
    @classmethod
    def validate_base_price(cls, v):
        if v is not None and v <= 0:
            raise ValueError("Base price must be a positive number")
        return v

    @field_validator("available_seats")
    @classmethod
    def validate_available_seats(cls, v):
        if v is not None and v < 0:
            raise ValueError("Available seats cannot be negative")
        return v


class ScheduleResponse(ScheduleBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class SeatBase(BaseModel):
    schedule_id: str
    seat_number: str
    seat_type: SeatType
    price_modifier: float
    status: SeatStatus

    @field_validator("price_modifier")
    @classmethod
    def validate_price_modifier(cls, v):
        if v < 0:
            raise ValueError("Price modifier must be non-negative")
        return v


class SeatCreate(SeatBase):
    pass


class SeatUpdate(BaseModel):
    schedule_id: Optional[str] = None
    seat_number: Optional[str] = None
    seat_type: Optional[SeatType] = None
    price_modifier: Optional[float] = None
    status: Optional[SeatStatus] = None

    @field_validator("price_modifier")
    @classmethod
    def validate_price_modifier(cls, v):
        if v is not None and v < 0:
            raise ValueError("Price modifier must be non-negative")
        return v


class SeatResponse(SeatBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class BusResponseNested(BaseModel):
    id: str
    bus_number: str
    bus_type: str
    amenities: Optional[dict] = None

    model_config = ConfigDict(from_attributes=True)


class RouteResponseNested(BaseModel):
    id: str
    origin_city: str
    destination_city: str
    distance_km: float
    estimated_duration_minutes: int

    model_config = ConfigDict(from_attributes=True)


class SeatResponseNested(BaseModel):
    id: str
    seat_number: str
    seat_type: SeatType
    status: SeatStatus
    price_modifier: float

    model_config = ConfigDict(from_attributes=True)


class ScheduleDetailResponse(BaseModel):
    id: str
    bus_id: str
    route_id: str
    departure_datetime: datetime
    arrival_datetime: datetime
    base_price: float
    available_seats: int
    status: ScheduleStatus
    created_at: datetime
    updated_at: datetime
    bus: BusResponseNested
    route: RouteResponseNested
    seats: List[SeatResponseNested]

    model_config = ConfigDict(from_attributes=True)


class GenerateSeatsRequest(BaseModel):
    pass


class GenerateSeatsResponse(BaseModel):
    schedule_id: str
    seats_generated: int
    message: str

    model_config = ConfigDict(from_attributes=True)