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, BookingDetailResponse,
    TravelerCreate, TravelerUpdate, TravelerResponse,
    TourscheduleCreate, TourscheduleUpdate, TourscheduleResponse, TourScheduleFullDetailResponse,
    TourschedulehotelCreate, TourschedulehotelUpdate, TourschedulehotelResponse,
    TourscheduletransportationCreate, TourscheduletransportationUpdate, TourscheduletransportationResponse
)

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


# Booking routes
@router.post(
    "/",
    response_model=BookingResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Booking",
    description="Creates a new booking for a tour schedule. Validates minimum lead time (48 hours), available slots, and customer/tour schedule existence. Returns 409 if booking number already exists, 400 if validation fails.",
)
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 customer_id, tour_schedule_id, booking_status, and payment_status.",
)
def list_bookings_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    customer_id: Optional[str] = None,
    tour_schedule_id: Optional[str] = None,
    booking_status: Optional[str] = None,
    payment_status: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_bookings(db, limit, offset, customer_id, tour_schedule_id, booking_status, payment_status)


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


@router.put(
    "/{booking_id}",
    response_model=BookingResponse,
    summary="Update Booking",
    description="Updates an existing booking. Validates referenced entities (booking_agent, discount) if provided. Returns 404 if booking not found.",
)
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 by ID. Cascades to related travelers, payments, invoice, and documents. Returns 404 if booking not found.",
)
def delete_booking_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.delete_booking(db, booking_id)


@router.get(
    "/{booking_id}/details",
    response_model=BookingDetailResponse,
    summary="Get Booking Details",
    description="Returns detailed booking information including customer, tour schedule, tour package, tour guide, booking agent, discount, travelers, payments, and invoice with line items. Uses eager loading to prevent 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.post(
    "/{booking_id}/confirm",
    response_model=BookingResponse,
    summary="Confirm Booking",
    description="Confirms a pending booking and updates tour schedule capacity. Validates available slots and booking status. Returns 400 if booking is not pending or insufficient slots available.",
)
def confirm_booking_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.confirm_booking(db, booking_id)


# Traveler routes
traveler_router = APIRouter(prefix="/travelers", tags=["Travelers"])


@traveler_router.post(
    "/",
    response_model=TravelerResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Traveler",
    description="Creates a new traveler record for a booking. Validates booking existence. Returns 404 if booking not found.",
)
def create_traveler_route(data: TravelerCreate, db: Session = Depends(get_db)):
    return handler.create_traveler(db, data)


@traveler_router.get(
    "/",
    response_model=List[TravelerResponse],
    summary="List Travelers",
    description="Returns a paginated list of travelers. Supports optional filters for booking_id and traveler_type.",
)
def list_travelers_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    booking_id: Optional[str] = None,
    traveler_type: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_travelers(db, limit, offset, booking_id, traveler_type)


@traveler_router.get(
    "/{traveler_id}",
    response_model=TravelerResponse,
    summary="Get Traveler",
    description="Returns a single traveler by ID. Returns 404 if traveler not found.",
)
def get_traveler_route(traveler_id: str, db: Session = Depends(get_db)):
    return handler.get_traveler(db, traveler_id)


@traveler_router.put(
    "/{traveler_id}",
    response_model=TravelerResponse,
    summary="Update Traveler",
    description="Updates an existing traveler record. Returns 404 if traveler not found.",
)
def update_traveler_route(traveler_id: str, data: TravelerUpdate, db: Session = Depends(get_db)):
    return handler.update_traveler(db, traveler_id, data)


@traveler_router.delete(
    "/{traveler_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Traveler",
    description="Deletes a traveler by ID. Returns 404 if traveler not found.",
)
def delete_traveler_route(traveler_id: str, db: Session = Depends(get_db)):
    return handler.delete_traveler(db, traveler_id)


router.include_router(traveler_router)


# Tour schedule routes
schedule_router = APIRouter(prefix="/tour-schedules", tags=["Tour Schedules"])


@schedule_router.post(
    "/",
    response_model=TourscheduleResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Tour Schedule",
    description="Creates a new tour schedule for a tour package. Validates tour package and tour guide existence, departure date is in the future, and return date is after departure date. Returns 404 if tour package not found, 400 if validation fails.",
)
def create_tourschedule_route(data: TourscheduleCreate, db: Session = Depends(get_db)):
    return handler.create_tourschedule(db, data)


@schedule_router.get(
    "/",
    response_model=List[TourscheduleResponse],
    summary="List Tour Schedules",
    description="Returns a paginated list of tour schedules. Supports optional filters for tour_package_id, tour_guide_id, and status.",
)
def list_tourschedules_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    tour_package_id: Optional[str] = None,
    tour_guide_id: Optional[str] = None,
    status: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_tourschedules(db, limit, offset, tour_package_id, tour_guide_id, status)


@schedule_router.get(
    "/{tourschedule_id}",
    response_model=TourscheduleResponse,
    summary="Get Tour Schedule",
    description="Returns a single tour schedule by ID. Returns 404 if tour schedule not found.",
)
def get_tourschedule_route(tourschedule_id: str, db: Session = Depends(get_db)):
    return handler.get_tourschedule(db, tourschedule_id)


@schedule_router.put(
    "/{tourschedule_id}",
    response_model=TourscheduleResponse,
    summary="Update Tour Schedule",
    description="Updates an existing tour schedule. Validates tour guide existence if provided. Returns 404 if tour schedule not found.",
)
def update_tourschedule_route(tourschedule_id: str, data: TourscheduleUpdate, db: Session = Depends(get_db)):
    return handler.update_tourschedule(db, tourschedule_id, data)


@schedule_router.delete(
    "/{tourschedule_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Tour Schedule",
    description="Deletes a tour schedule by ID. Cascades to related bookings, hotels, and transportations. Returns 404 if tour schedule not found.",
)
def delete_tourschedule_route(tourschedule_id: str, db: Session = Depends(get_db)):
    return handler.delete_tourschedule(db, tourschedule_id)


@schedule_router.get(
    "/{schedule_id}/details",
    response_model=TourScheduleFullDetailResponse,
    summary="Get Tour Schedule Details",
    description="Returns detailed tour schedule information including tour package, category, tour guide, assigned hotels with room types, and assigned transportations. Uses eager loading to prevent N+1 queries.",
)
def get_tourschedule_details_route(schedule_id: str, db: Session = Depends(get_db)):
    return handler.get_tourschedule_details(db, schedule_id)


@schedule_router.post(
    "/{schedule_id}/assign-guide",
    response_model=TourscheduleResponse,
    summary="Assign Guide To Schedule",
    description="Assigns a tour guide to a tour schedule. Validates tour guide existence. Returns 404 if tour schedule or guide not found.",
)
def assign_guide_route(schedule_id: str, guide_id: str = Query(...), db: Session = Depends(get_db)):
    return handler.assign_guide_to_schedule(db, schedule_id, guide_id)


@schedule_router.post(
    "/{schedule_id}/complete",
    response_model=TourscheduleResponse,
    summary="Complete Tour Schedule",
    description="Marks a tour schedule as completed and updates all confirmed bookings to completed status. Returns 400 if schedule is not in confirmed or in_progress status.",
)
def complete_schedule_route(schedule_id: str, db: Session = Depends(get_db)):
    return handler.complete_tour_schedule(db, schedule_id)


router.include_router(schedule_router)


# Tour schedule hotel routes
hotel_router = APIRouter(prefix="/tour-schedule-hotels", tags=["Tour Schedule Hotels"])


@hotel_router.post(
    "/",
    response_model=TourschedulehotelResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Tour Schedule Hotel",
    description="Creates a hotel booking for a tour schedule. Validates tour schedule, hotel, and room type existence. Validates check-out date is after check-in date. Returns 404 if entities not found, 400 if validation fails.",
)
def create_tourschedulehotel_route(data: TourschedulehotelCreate, db: Session = Depends(get_db)):
    return handler.create_tourschedulehotel(db, data)


@hotel_router.get(
    "/",
    response_model=List[TourschedulehotelResponse],
    summary="List Tour Schedule Hotels",
    description="Returns a paginated list of tour schedule hotel bookings. Supports optional filters for tour_schedule_id, hotel_id, and booking_status.",
)
def list_tourschedulehotels_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    tour_schedule_id: Optional[str] = None,
    hotel_id: Optional[str] = None,
    booking_status: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_tourschedulehotels(db, limit, offset, tour_schedule_id, hotel_id, booking_status)


@hotel_router.get(
    "/{tourschedulehotel_id}",
    response_model=TourschedulehotelResponse,
    summary="Get Tour Schedule Hotel",
    description="Returns a single tour schedule hotel booking by ID. Returns 404 if not found.",
)
def get_tourschedulehotel_route(tourschedulehotel_id: str, db: Session = Depends(get_db)):
    return handler.get_tourschedulehotel(db, tourschedulehotel_id)


@hotel_router.put(
    "/{tourschedulehotel_id}",
    response_model=TourschedulehotelResponse,
    summary="Update Tour Schedule Hotel",
    description="Updates an existing tour schedule hotel booking. Validates room type existence if provided. Returns 404 if not found.",
)
def update_tourschedulehotel_route(tourschedulehotel_id: str, data: TourschedulehotelUpdate, db: Session = Depends(get_db)):
    return handler.update_tourschedulehotel(db, tourschedulehotel_id, data)


@hotel_router.delete(
    "/{tourschedulehotel_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Tour Schedule Hotel",
    description="Deletes a tour schedule hotel booking by ID. Returns 404 if not found.",
)
def delete_tourschedulehotel_route(tourschedulehotel_id: str, db: Session = Depends(get_db)):
    return handler.delete_tourschedulehotel(db, tourschedulehotel_id)


router.include_router(hotel_router)


# Tour schedule transportation routes
transport_router = APIRouter(prefix="/tour-schedule-transportations", tags=["Tour Schedule Transportations"])


@transport_router.post(
    "/",
    response_model=TourscheduletransportationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Tour Schedule Transportation",
    description="Creates a transportation booking for a tour schedule. Validates tour schedule and transportation existence. Validates arrival datetime is after departure datetime. Returns 404 if entities not found, 400 if validation fails.",
)
def create_tourscheduletransportation_route(data: TourscheduletransportationCreate, db: Session = Depends(get_db)):
    return handler.create_tourscheduletransportation(db, data)


@transport_router.get(
    "/",
    response_model=List[TourscheduletransportationResponse],
    summary="List Tour Schedule Transportations",
    description="Returns a paginated list of tour schedule transportation bookings. Supports optional filters for tour_schedule_id, transportation_id, and booking_status.",
)
def list_tourscheduletransportations_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    tour_schedule_id: Optional[str] = None,
    transportation_id: Optional[str] = None,
    booking_status: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_tourscheduletransportations(db, limit, offset, tour_schedule_id, transportation_id, booking_status)


@transport_router.get(
    "/{tourscheduletransportation_id}",
    response_model=TourscheduletransportationResponse,
    summary="Get Tour Schedule Transportation",
    description="Returns a single tour schedule transportation booking by ID. Returns 404 if not found.",
)
def get_tourscheduletransportation_route(tourscheduletransportation_id: str, db: Session = Depends(get_db)):
    return handler.get_tourscheduletransportation(db, tourscheduletransportation_id)


@transport_router.put(
    "/{tourscheduletransportation_id}",
    response_model=TourscheduletransportationResponse,
    summary="Update Tour Schedule Transportation",
    description="Updates an existing tour schedule transportation booking. Returns 404 if not found.",
)
def update_tourscheduletransportation_route(tourscheduletransportation_id: str, data: TourscheduletransportationUpdate, db: Session = Depends(get_db)):
    return handler.update_tourscheduletransportation(db, tourscheduletransportation_id, data)


@transport_router.delete(
    "/{tourscheduletransportation_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Tour Schedule Transportation",
    description="Deletes a tour schedule transportation booking by ID. Returns 404 if not found.",
)
def delete_tourscheduletransportation_route(tourscheduletransportation_id: str, db: Session = Depends(get_db)):
    return handler.delete_tourscheduletransportation(db, tourscheduletransportation_id)


router.include_router(transport_router)