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 (
    CategoryCreate,
    CategoryUpdate,
    CategoryResponse,
    DestinationCreate,
    DestinationUpdate,
    DestinationResponse,
    SeasonCreate,
    SeasonUpdate,
    SeasonResponse,
    AmenityCreate,
    AmenityUpdate,
    AmenityResponse,
    TourpackageCreate,
    TourpackageUpdate,
    TourpackageResponse,
    TourpackagedestinationCreate,
    TourpackagedestinationUpdate,
    TourpackagedestinationResponse,
    TourpackageamenityCreate,
    TourpackageamenityUpdate,
    TourpackageamenityResponse,
    ItineraryCreate,
    ItineraryUpdate,
    ItineraryResponse,
    TourpackageDetailResponse,
)

router = APIRouter(prefix="/tour-catalog", tags=["Tour Catalog"])


# Category Routes
@router.post(
    "/categories",
    response_model=CategoryResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Category",
    description="Creates a new tour package category. Returns 409 if a category with the same slug already exists.",
)
def create_category_route(data: CategoryCreate, db: Session = Depends(get_db)):
    return handler.create_category(db, data)


@router.get(
    "/categories",
    response_model=List[CategoryResponse],
    summary="List Categories",
    description="Returns a paginated list of tour package categories. Supports optional filters for active status and search by name.",
)
def list_categories_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    is_active: Optional[bool] = None,
    search: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_categories(db, limit, offset, is_active, search)


@router.get(
    "/categories/{category_id}",
    response_model=CategoryResponse,
    summary="Get Category",
    description="Returns a single category by ID. Returns 404 if the category does not exist.",
)
def get_category_route(category_id: str, db: Session = Depends(get_db)):
    return handler.get_category(db, category_id)


@router.put(
    "/categories/{category_id}",
    response_model=CategoryResponse,
    summary="Update Category",
    description="Updates an existing category. Returns 404 if the category does not exist, 409 if the new slug conflicts with another category.",
)
def update_category_route(category_id: str, data: CategoryUpdate, db: Session = Depends(get_db)):
    return handler.update_category(db, category_id, data)


@router.delete(
    "/categories/{category_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Category",
    description="Deletes a category by ID. Returns 404 if the category does not exist.",
)
def delete_category_route(category_id: str, db: Session = Depends(get_db)):
    return handler.delete_category(db, category_id)


# Destination Routes
@router.post(
    "/destinations",
    response_model=DestinationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Destination",
    description="Creates a new destination. Returns 409 if a destination with the same slug already exists.",
)
def create_destination_route(data: DestinationCreate, db: Session = Depends(get_db)):
    return handler.create_destination(db, data)


@router.get(
    "/destinations",
    response_model=List[DestinationResponse],
    summary="List Destinations",
    description="Returns a paginated list of destinations. Supports optional filters for active status, country, and search by name.",
)
def list_destinations_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    is_active: Optional[bool] = None,
    country: Optional[str] = None,
    search: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_destinations(db, limit, offset, is_active, country, search)


@router.get(
    "/destinations/{destination_id}",
    response_model=DestinationResponse,
    summary="Get Destination",
    description="Returns a single destination by ID. Returns 404 if the destination does not exist.",
)
def get_destination_route(destination_id: str, db: Session = Depends(get_db)):
    return handler.get_destination(db, destination_id)


@router.put(
    "/destinations/{destination_id}",
    response_model=DestinationResponse,
    summary="Update Destination",
    description="Updates an existing destination. Returns 404 if the destination does not exist, 409 if the new slug conflicts with another destination.",
)
def update_destination_route(destination_id: str, data: DestinationUpdate, db: Session = Depends(get_db)):
    return handler.update_destination(db, destination_id, data)


@router.delete(
    "/destinations/{destination_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Destination",
    description="Deletes a destination by ID. Returns 404 if the destination does not exist.",
)
def delete_destination_route(destination_id: str, db: Session = Depends(get_db)):
    return handler.delete_destination(db, destination_id)


# Season Routes
@router.post(
    "/seasons",
    response_model=SeasonResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Season",
    description="Creates a new seasonal pricing period. Validates that end date is after start date.",
)
def create_season_route(data: SeasonCreate, db: Session = Depends(get_db)):
    return handler.create_season(db, data)


@router.get(
    "/seasons",
    response_model=List[SeasonResponse],
    summary="List Seasons",
    description="Returns a paginated list of seasons ordered by start date. Supports optional filter by season type.",
)
def list_seasons_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    season_type: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_seasons(db, limit, offset, season_type)


@router.get(
    "/seasons/{season_id}",
    response_model=SeasonResponse,
    summary="Get Season",
    description="Returns a single season by ID. Returns 404 if the season does not exist.",
)
def get_season_route(season_id: str, db: Session = Depends(get_db)):
    return handler.get_season(db, season_id)


@router.put(
    "/seasons/{season_id}",
    response_model=SeasonResponse,
    summary="Update Season",
    description="Updates an existing season. Returns 404 if the season does not exist.",
)
def update_season_route(season_id: str, data: SeasonUpdate, db: Session = Depends(get_db)):
    return handler.update_season(db, season_id, data)


@router.delete(
    "/seasons/{season_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Season",
    description="Deletes a season by ID. Returns 404 if the season does not exist.",
)
def delete_season_route(season_id: str, db: Session = Depends(get_db)):
    return handler.delete_season(db, season_id)


# Amenity Routes
@router.post(
    "/amenities",
    response_model=AmenityResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Amenity",
    description="Creates a new amenity that can be associated with tour packages or hotels.",
)
def create_amenity_route(data: AmenityCreate, db: Session = Depends(get_db)):
    return handler.create_amenity(db, data)


@router.get(
    "/amenities",
    response_model=List[AmenityResponse],
    summary="List Amenities",
    description="Returns a paginated list of amenities. Supports optional filters for amenity type and search by name.",
)
def list_amenities_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    amenity_type: Optional[str] = None,
    search: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_amenities(db, limit, offset, amenity_type, search)


@router.get(
    "/amenities/{amenity_id}",
    response_model=AmenityResponse,
    summary="Get Amenity",
    description="Returns a single amenity by ID. Returns 404 if the amenity does not exist.",
)
def get_amenity_route(amenity_id: str, db: Session = Depends(get_db)):
    return handler.get_amenity(db, amenity_id)


@router.put(
    "/amenities/{amenity_id}",
    response_model=AmenityResponse,
    summary="Update Amenity",
    description="Updates an existing amenity. Returns 404 if the amenity does not exist.",
)
def update_amenity_route(amenity_id: str, data: AmenityUpdate, db: Session = Depends(get_db)):
    return handler.update_amenity(db, amenity_id, data)


@router.delete(
    "/amenities/{amenity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Amenity",
    description="Deletes an amenity by ID. Returns 404 if the amenity does not exist.",
)
def delete_amenity_route(amenity_id: str, db: Session = Depends(get_db)):
    return handler.delete_amenity(db, amenity_id)


# Tourpackage Routes
@router.post(
    "/tour-packages",
    response_model=TourpackageResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Tour Package",
    description="Creates a new tour package. Validates that the category exists and the slug is unique. Returns 404 if category not found, 409 if slug already exists.",
)
def create_tourpackage_route(data: TourpackageCreate, db: Session = Depends(get_db)):
    return handler.create_tourpackage(db, data)


@router.get(
    "/tour-packages",
    response_model=List[TourpackageResponse],
    summary="List Tour Packages",
    description="Returns a paginated list of tour packages. Supports optional filters for active status, featured status, category, difficulty level, and search by name.",
)
def list_tourpackages_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    is_active: Optional[bool] = None,
    is_featured: Optional[bool] = None,
    category_id: Optional[str] = None,
    difficulty_level: Optional[str] = None,
    search: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_tourpackages(db, limit, offset, is_active, is_featured, category_id, difficulty_level, search)


@router.get(
    "/tour-packages/{tourpackage_id}",
    response_model=TourpackageResponse,
    summary="Get Tour Package",
    description="Returns a single tour package by ID. Returns 404 if the tour package does not exist.",
)
def get_tourpackage_route(tourpackage_id: str, db: Session = Depends(get_db)):
    return handler.get_tourpackage(db, tourpackage_id)


@router.get(
    "/tour-packages/{tourpackage_id}/details",
    response_model=TourpackageDetailResponse,
    summary="Get Tour Package Details",
    description="Returns a tour package with all related data including category, itineraries, destinations, and amenities. Uses eager loading to prevent N+1 queries. Returns 404 if the tour package does not exist.",
)
def get_tourpackage_details_route(tourpackage_id: str, db: Session = Depends(get_db)):
    return handler.get_tourpackage_details(db, tourpackage_id)


@router.put(
    "/tour-packages/{tourpackage_id}",
    response_model=TourpackageResponse,
    summary="Update Tour Package",
    description="Updates an existing tour package. Validates that the category exists if changed and the slug is unique if changed. Returns 404 if tour package or category not found, 409 if new slug conflicts.",
)
def update_tourpackage_route(tourpackage_id: str, data: TourpackageUpdate, db: Session = Depends(get_db)):
    return handler.update_tourpackage(db, tourpackage_id, data)


@router.delete(
    "/tour-packages/{tourpackage_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Tour Package",
    description="Deletes a tour package by ID. Cascades to related itineraries, destinations, and amenities. Returns 404 if the tour package does not exist.",
)
def delete_tourpackage_route(tourpackage_id: str, db: Session = Depends(get_db)):
    return handler.delete_tourpackage(db, tourpackage_id)


# Tourpackagedestination Routes
@router.post(
    "/tour-package-destinations",
    response_model=TourpackagedestinationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Tour Package Destination",
    description="Associates a destination with a tour package. Validates that both tour package and destination exist. Returns 404 if either not found.",
)
def create_tourpackagedestination_route(data: TourpackagedestinationCreate, db: Session = Depends(get_db)):
    return handler.create_tourpackagedestination(db, data)


@router.get(
    "/tour-package-destinations",
    response_model=List[TourpackagedestinationResponse],
    summary="List Tour Package Destinations",
    description="Returns a paginated list of tour package destination associations. Supports optional filters for tour package ID and destination ID.",
)
def list_tourpackagedestinations_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    tour_package_id: Optional[str] = None,
    destination_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_tourpackagedestinations(db, limit, offset, tour_package_id, destination_id)


@router.get(
    "/tour-package-destinations/{tpd_id}",
    response_model=TourpackagedestinationResponse,
    summary="Get Tour Package Destination",
    description="Returns a single tour package destination association by ID. Returns 404 if not found.",
)
def get_tourpackagedestination_route(tpd_id: str, db: Session = Depends(get_db)):
    return handler.get_tourpackagedestination(db, tpd_id)


@router.put(
    "/tour-package-destinations/{tpd_id}",
    response_model=TourpackagedestinationResponse,
    summary="Update Tour Package Destination",
    description="Updates an existing tour package destination association. Validates that tour package and destination exist if changed. Returns 404 if not found.",
)
def update_tourpackagedestination_route(tpd_id: str, data: TourpackagedestinationUpdate, db: Session = Depends(get_db)):
    return handler.update_tourpackagedestination(db, tpd_id, data)


@router.delete(
    "/tour-package-destinations/{tpd_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Tour Package Destination",
    description="Deletes a tour package destination association by ID. Returns 404 if not found.",
)
def delete_tourpackagedestination_route(tpd_id: str, db: Session = Depends(get_db)):
    return handler.delete_tourpackagedestination(db, tpd_id)


# Tourpackageamenity Routes
@router.post(
    "/tour-package-amenities",
    response_model=TourpackageamenityResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Tour Package Amenity",
    description="Associates an amenity with a tour package. Validates that both tour package and amenity exist. Returns 404 if either not found.",
)
def create_tourpackageamenity_route(data: TourpackageamenityCreate, db: Session = Depends(get_db)):
    return handler.create_tourpackageamenity(db, data)


@router.get(
    "/tour-package-amenities",
    response_model=List[TourpackageamenityResponse],
    summary="List Tour Package Amenities",
    description="Returns a paginated list of tour package amenity associations. Supports optional filters for tour package ID and amenity ID.",
)
def list_tourpackageamenities_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    tour_package_id: Optional[str] = None,
    amenity_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_tourpackageamenities(db, limit, offset, tour_package_id, amenity_id)


@router.get(
    "/tour-package-amenities/{tpa_id}",
    response_model=TourpackageamenityResponse,
    summary="Get Tour Package Amenity",
    description="Returns a single tour package amenity association by ID. Returns 404 if not found.",
)
def get_tourpackageamenity_route(tpa_id: str, db: Session = Depends(get_db)):
    return handler.get_tourpackageamenity(db, tpa_id)


@router.put(
    "/tour-package-amenities/{tpa_id}",
    response_model=TourpackageamenityResponse,
    summary="Update Tour Package Amenity",
    description="Updates an existing tour package amenity association. Validates that tour package and amenity exist if changed. Returns 404 if not found.",
)
def update_tourpackageamenity_route(tpa_id: str, data: TourpackageamenityUpdate, db: Session = Depends(get_db)):
    return handler.update_tourpackageamenity(db, tpa_id, data)


@router.delete(
    "/tour-package-amenities/{tpa_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Tour Package Amenity",
    description="Deletes a tour package amenity association by ID. Returns 404 if not found.",
)
def delete_tourpackageamenity_route(tpa_id: str, db: Session = Depends(get_db)):
    return handler.delete_tourpackageamenity(db, tpa_id)


# Itinerary Routes
@router.post(
    "/itineraries",
    response_model=ItineraryResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Itinerary",
    description="Creates a new itinerary day for a tour package. Validates that the tour package exists. Returns 404 if tour package not found.",
)
def create_itinerary_route(data: ItineraryCreate, db: Session = Depends(get_db)):
    return handler.create_itinerary(db, data)


@router.get(
    "/itineraries",
    response_model=List[ItineraryResponse],
    summary="List Itineraries",
    description="Returns a paginated list of itineraries ordered by day number. Supports optional filter for tour package ID.",
)
def list_itineraries_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    tour_package_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_itineraries(db, limit, offset, tour_package_id)


@router.get(
    "/itineraries/{itinerary_id}",
    response_model=ItineraryResponse,
    summary="Get Itinerary",
    description="Returns a single itinerary by ID. Returns 404 if the itinerary does not exist.",
)
def get_itinerary_route(itinerary_id: str, db: Session = Depends(get_db)):
    return handler.get_itinerary(db, itinerary_id)


@router.put(
    "/itineraries/{itinerary_id}",
    response_model=ItineraryResponse,
    summary="Update Itinerary",
    description="Updates an existing itinerary. Validates that the tour package exists if changed. Returns 404 if itinerary or tour package not found.",
)
def update_itinerary_route(itinerary_id: str, data: ItineraryUpdate, db: Session = Depends(get_db)):
    return handler.update_itinerary(db, itinerary_id, data)


@router.delete(
    "/itineraries/{itinerary_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Itinerary",
    description="Deletes an itinerary by ID. Returns 404 if the itinerary does not exist.",
)
def delete_itinerary_route(itinerary_id: str, db: Session = Depends(get_db)):
    return handler.delete_itinerary(db, itinerary_id)