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 (
    PassengerCreate, PassengerUpdate, PassengerResponse,
    BookingCreate, BookingUpdate, BookingResponse,
    BookingDetailResponse, PassengerDetailResponse,
    BookingStatus, PaymentStatus
)

router = APIRouter()

# Passenger routes
passenger_router = APIRouter(prefix="/passengers", tags=["Passengers"])


@passenger_router.post(
    "/",
    response_model=PassengerResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Passenger",
    description="Creates a new passenger record with personal and contact information. Returns 409 if a passenger with the same email already exists. Validates passport number format if provided (alphanumeric, 6-12 characters).",
)
def create_passenger_route(data: PassengerCreate, db: Session = Depends(get_db)):
    return handler.create_passenger(db, data)


@passenger_router.get(
    "/",
    response_model=List[PassengerResponse],
    summary="List Passengers",
    description="Returns a paginated list of passengers. Supports optional search filter on first name, last name, email, and passport number fields.",
)
def list_passengers_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    search: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_passengers(db, limit, offset, search)


@passenger_router.get(
    "/{passenger_id}",
    response_model=PassengerResponse,
    summary="Get Passenger",
    description="Returns a single passenger by ID. Returns 404 if the passenger does not exist.",
)
def get_passenger_route(passenger_id: str, db: Session = Depends(get_db)):
    return handler.get_passenger(db, passenger_id)


@passenger_router.put(
    "/{passenger_id}",
    response_model=PassengerResponse,
    summary="Update Passenger",
    description="Updates an existing passenger record. Only provided fields are updated. Returns 404 if the passenger does not exist. Returns 409 if the new email is already in use by another passenger.",
)
def update_passenger_route(
    passenger_id: str, data: PassengerUpdate, db: Session = Depends(get_db)
):
    return handler.update_passenger(db, passenger_id, data)


@passenger_router.delete(
    "/{passenger_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Passenger",
    description="Deletes a passenger record. Returns 404 if the passenger does not exist. Returns 400 if the passenger has existing bookings.",
)
def delete_passenger_route(passenger_id: str, db: Session = Depends(get_db)):
    return handler.delete_passenger(db, passenger_id)


@passenger_router.get(
    "/{passenger_id}/details",
    response_model=PassengerDetailResponse,
    summary="Get Passenger Details",
    description="Returns detailed passenger information including all bookings with flight details, origin/destination airports, and booking status. Returns 404 if the passenger does not exist.",
)
def get_passenger_details_route(passenger_id: str, db: Session = Depends(get_db)):
    return handler.get_passenger_details(db, passenger_id)


# Booking routes
booking_router = APIRouter(prefix="/bookings", tags=["Bookings"])


@booking_router.post(
    "/",
    response_model=BookingResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Booking",
    description="Creates a new flight booking for a passenger. Validates that the flight is scheduled and not in the past, the seat belongs to the flight's aircraft and is available, and the flight is not fully booked. Automatically generates a unique 6-character alphanumeric booking reference. Returns 400 for validation failures, 404 if passenger/flight/seat/fare class not found, 409 if seat is already booked.",
)
def create_booking_route(data: BookingCreate, db: Session = Depends(get_db)):
    return handler.create_booking(db, data)


@booking_router.get(
    "/",
    response_model=List[BookingResponse],
    summary="List Bookings",
    description="Returns a paginated list of bookings. Supports optional filters for booking reference search, booking status, payment status, passenger ID, and flight ID.",
)
def list_bookings_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    search: Optional[str] = None,
    booking_status: Optional[BookingStatus] = Query(None),
    payment_status: Optional[PaymentStatus] = Query(None),
    passenger_id: Optional[str] = None,
    flight_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_bookings(
        db, limit, offset, search,
        booking_status.value if booking_status else None,
        payment_status.value if payment_status else None,
        passenger_id, flight_id
    )


@booking_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)


@booking_router.put(
    "/{booking_id}",
    response_model=BookingResponse,
    summary="Update Booking",
    description="Updates an existing booking record. Only provided fields are updated. Validates flight status, seat availability, and aircraft compatibility when changing flight or seat. Returns 404 if booking/passenger/flight/seat/fare class not found, 400 for validation failures, 409 if new seat is already booked.",
)
def update_booking_route(
    booking_id: str, data: BookingUpdate, db: Session = Depends(get_db)
):
    return handler.update_booking(db, booking_id, data)


@booking_router.delete(
    "/{booking_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Booking",
    description="Deletes a booking record. 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)


@booking_router.get(
    "/{booking_id}/details",
    response_model=BookingDetailResponse,
    summary="Get Booking Details",
    description="Returns comprehensive booking information including passenger details, flight information with route and aircraft details, seat assignment, and fare class information. Returns 404 if the booking does not exist.",
)
def get_booking_details_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.get_booking_details(db, booking_id)


@booking_router.post(
    "/{booking_id}/cancel",
    response_model=BookingResponse,
    summary="Cancel Booking",
    description="Cancels a booking and updates payment status to Refunded if payment was completed. Returns 400 if booking is already cancelled or has status Checked In/Boarded. Returns 404 if the booking does not exist.",
)
def cancel_booking_route(booking_id: str, db: Session = Depends(get_db)):
    return handler.cancel_booking(db, booking_id)


@booking_router.post(
    "/{booking_id}/change-seat",
    response_model=BookingResponse,
    summary="Change Booking Seat",
    description="Changes the seat assignment for a booking. Validates that the new seat belongs to the flight's aircraft and is available. Only allowed for bookings with status Confirmed or Pending. Returns 400 for validation failures, 404 if booking/seat not found, 409 if new seat is already booked.",
)
def change_booking_seat_route(
    booking_id: str, new_seat_id: str = Query(...), db: Session = Depends(get_db)
):
    return handler.change_booking_seat(db, booking_id, new_seat_id)


@booking_router.post(
    "/{booking_id}/change-flight",
    response_model=BookingResponse,
    summary="Change Booking Flight",
    description="Changes the flight for a booking and clears the seat assignment. Validates that the new flight is scheduled, not in the past, and not fully booked. Only allowed for bookings with status Confirmed or Pending. Returns 400 for validation failures, 404 if booking/flight not found.",
)
def change_booking_flight_route(
    booking_id: str, new_flight_id: str = Query(...), db: Session = Depends(get_db)
):
    return handler.change_booking_flight(db, booking_id, new_flight_id)


router.include_router(passenger_router)
router.include_router(booking_router)