from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional, List
from utils.utils import get_db
from . import handler
from .schema import (
    BookingCreate,
    BookingUpdate,
    BookingResponse,
    BookingseatCreate,
    BookingseatUpdate,
    BookingseatResponse,
    TicketCreate,
    TicketUpdate,
    TicketResponse,
    BookingDetailResponse,
    BookingStatus,
    TicketValidityStatus,
)

router = APIRouter(prefix="/bookings", tags=["Booking Management"])


@router.post(
    "/",
    response_model=BookingResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Booking",
    description="Creates a new booking record after successful payment. Validates that the reservation, user, and schedule exist. Returns 409 if the booking reference already exists.",
)
def create_booking_route(data: BookingCreate, db: Session = Depends(get_db)):
    return handler.create_booking(db, data)


@router.get(
    "/",
    response_model=List[BookingResponse],
    summary="List Bookings",
    description="Returns a paginated list of bookings. Supports optional filters for user_id, schedule_id, and status.",
)
def list_bookings_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    user_id: Optional[str] = Query(None),
    schedule_id: Optional[str] = Query(None),
    status: Optional[BookingStatus] = Query(None),
    db: Session = Depends(get_db),
):
    return handler.list_bookings(db, limit, offset, user_id, schedule_id, status.value if status else None)


@router.get(
    "/{booking_id}",
    response_model=BookingResponse,
    summary="Get Booking",
    description="Returns a single booking by ID. Returns 404 if the booking does not exist.",
)
def get_booking_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.get_booking(db, booking_id)


@router.get(
    "/{booking_id}/details",
    response_model=BookingDetailResponse,
    summary="Get Booking Details",
    description="Returns comprehensive booking details including user information, schedule with bus and route details, booked seats with seat types, ticket information, and payment history. All related data is eagerly loaded to avoid N+1 queries.",
)
def get_booking_details_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.get_booking_details(db, booking_id)


@router.put(
    "/{booking_id}",
    response_model=BookingResponse,
    summary="Update Booking",
    description="Updates an existing booking. Validates foreign key references if they are being changed. Returns 404 if the booking does not exist, 409 if the new booking reference already exists.",
)
def update_booking_route(booking_id: str, data: BookingUpdate, db: Session = Depends(get_db)):
    return handler.update_booking(db, booking_id, data)


@router.delete(
    "/{booking_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Booking",
    description="Deletes a booking and all associated records (booking seats, ticket, payments, cancellation) via cascade. Returns 404 if the booking does not exist.",
)
def delete_booking_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.delete_booking(db, booking_id)


@router.post(
    "/seats",
    response_model=BookingseatResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Booking Seat",
    description="Creates a booking seat record linking a booking to a seat. Validates that both the booking and seat exist. Returns 404 if either does not exist.",
)
def create_bookingseat_route(data: BookingseatCreate, db: Session = Depends(get_db)):
    return handler.create_bookingseat(db, data)


@router.get(
    "/seats",
    response_model=List[BookingseatResponse],
    summary="List Booking Seats",
    description="Returns a paginated list of booking seats. Supports optional filter for booking_id to retrieve all seats for a specific booking.",
)
def list_bookingseats_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    booking_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    return handler.list_bookingseats(db, limit, offset, booking_id)


@router.get(
    "/seats/{bookingseat_id}",
    response_model=BookingseatResponse,
    summary="Get Booking Seat",
    description="Returns a single booking seat by ID. Returns 404 if the booking seat does not exist.",
)
def get_bookingseat_route(bookingseat_id: str, db: Session = Depends(get_db)):
    return handler.get_bookingseat(db, bookingseat_id)


@router.put(
    "/seats/{bookingseat_id}",
    response_model=BookingseatResponse,
    summary="Update Booking Seat",
    description="Updates an existing booking seat. Validates foreign key references if they are being changed. Returns 404 if the booking seat, booking, or seat does not exist.",
)
def update_bookingseat_route(bookingseat_id: str, data: BookingseatUpdate, db: Session = Depends(get_db)):
    return handler.update_bookingseat(db, bookingseat_id, data)


@router.delete(
    "/seats/{bookingseat_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Booking Seat",
    description="Deletes a booking seat record. Returns 404 if the booking seat does not exist.",
)
def delete_bookingseat_route(bookingseat_id: str, db: Session = Depends(get_db)):
    return handler.delete_bookingseat(db, bookingseat_id)


@router.post(
    "/tickets",
    response_model=TicketResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Ticket",
    description="Creates a ticket for a confirmed booking. Validates that the booking exists and does not already have a ticket. Returns 404 if the booking does not exist, 409 if a ticket already exists for the booking or if the ticket number is already in use.",
)
def create_ticket_route(data: TicketCreate, db: Session = Depends(get_db)):
    return handler.create_ticket(db, data)


@router.get(
    "/tickets",
    response_model=List[TicketResponse],
    summary="List Tickets",
    description="Returns a paginated list of tickets. Supports optional filter for validity_status to retrieve tickets by their validity status.",
)
def list_tickets_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    validity_status: Optional[TicketValidityStatus] = Query(None),
    db: Session = Depends(get_db),
):
    return handler.list_tickets(db, limit, offset, validity_status.value if validity_status else None)


@router.get(
    "/tickets/{ticket_id}",
    response_model=TicketResponse,
    summary="Get Ticket",
    description="Returns a single ticket by ID. Returns 404 if the ticket does not exist.",
)
def get_ticket_route(ticket_id: str, db: Session = Depends(get_db)):
    return handler.get_ticket(db, ticket_id)


@router.put(
    "/tickets/{ticket_id}",
    response_model=TicketResponse,
    summary="Update Ticket",
    description="Updates an existing ticket. Validates that the booking exists if booking_id is being changed, and ensures ticket number uniqueness. Returns 404 if the ticket or booking does not exist, 409 if the new ticket number or booking already has a ticket.",
)
def update_ticket_route(ticket_id: str, data: TicketUpdate, db: Session = Depends(get_db)):
    return handler.update_ticket(db, ticket_id, data)


@router.delete(
    "/tickets/{ticket_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Ticket",
    description="Deletes a ticket record. Returns 404 if the ticket does not exist.",
)
def delete_ticket_route(ticket_id: str, db: Session = Depends(get_db)):
    return handler.delete_ticket(db, ticket_id)