"""Package validation helpers for adventure staycations."""

from __future__ import annotations

from datetime import date

from .exceptions import (
    InvalidDateRangeError,
    InvalidGuestCountError,
    PackageConfigError,
)
from .models import AdventurePackage, BookingRequest

SUPPORTED_CATEGORIES = {
    "TREKKING",
    "HILLS_STAYCATION",
    "JUNGLE_SAFARI",
    "LODGING",
}


class PackageBookingValidator:
    """Validates package configuration and booking requests."""

    @staticmethod
    def validate_package_config(package: AdventurePackage) -> None:
        if package.category not in SUPPORTED_CATEGORIES:
            raise PackageConfigError(f"Unsupported category: {package.category}")

        if package.min_nights <= 0 or package.max_nights <= 0:
            raise PackageConfigError("Night limits must be positive integers.")

        if package.min_nights > package.max_nights:
            raise PackageConfigError("min_nights cannot exceed max_nights.")

        if package.max_guests <= 0:
            raise PackageConfigError("max_guests must be positive.")

        if package.category in {"TREKKING", "JUNGLE_SAFARI"}:
            if not package.base_price_per_person:
                raise PackageConfigError(
                    "Per-person base price required for trekking and safari packages."
                )
        else:
            if not package.base_price_per_night:
                raise PackageConfigError(
                    "Per-night base price required for staycation or lodging packages."
                )

    @staticmethod
    def validate_dates(
        start_date: date, end_date: date, package: AdventurePackage
    ) -> int:
        PackageBookingValidator.validate_package_config(package)

        if start_date >= end_date:
            raise InvalidDateRangeError("End date must be after start date.")

        nights = (end_date - start_date).days
        if nights < package.min_nights or nights > package.max_nights:
            raise InvalidDateRangeError(
                f"Nights must be between {package.min_nights} and {package.max_nights}."
            )
        return nights

    @staticmethod
    def validate_guests(num_guests: int, package: AdventurePackage) -> None:
        PackageBookingValidator.validate_package_config(package)

        if num_guests <= 0 or num_guests > package.max_guests:
            raise InvalidGuestCountError(
                f"Guests must be between 1 and {package.max_guests}."
            )

    @staticmethod
    def create_booking_request(
        package: AdventurePackage,
        start_date: date,
        end_date: date,
        num_guests: int,
    ) -> BookingRequest:
        PackageBookingValidator.validate_dates(start_date, end_date, package)
        PackageBookingValidator.validate_guests(num_guests, package)
        return BookingRequest(
            package_id=package.package_id,
            start_date=start_date,
            end_date=end_date,
            num_guests=num_guests,
        )
