"""Pricing logic for adventure staycation bookings."""

from __future__ import annotations

from datetime import timedelta

from .exceptions import PackageConfigError
from .models import AdventurePackage, BookingRequest
from .packages import PackageBookingValidator


class AdventurePriceCalculator:
    """Calculates total price for a validated booking request."""

    WEEKEND_MULTIPLIER = 1.2
    PEAK_SEASON_MULTIPLIER = 1.3
    PEAK_MONTHS = {10, 11, 12, 1}

    def calculate_price(
        self, booking_request: BookingRequest, package: AdventurePackage
    ) -> float:
        nights = PackageBookingValidator.validate_dates(
            booking_request.start_date, booking_request.end_date, package
        )
        PackageBookingValidator.validate_guests(booking_request.num_guests, package)

        base = self._calculate_base_amount(booking_request, package, nights)

        if self._includes_weekend(booking_request):
            base *= self.WEEKEND_MULTIPLIER

        if self._is_peak_season(booking_request):
            base *= self.PEAK_SEASON_MULTIPLIER

        return round(base, 2)

    def _calculate_base_amount(
        self, booking_request: BookingRequest, package: AdventurePackage, nights: int
    ) -> float:
        category = package.category.upper()
        guests = booking_request.num_guests

        if category in {"HILLS_STAYCATION", "LODGING"}:
            if package.base_price_per_night is None:
                raise PackageConfigError(
                    "base_price_per_night must be configured for staycation/lodging packages."
                )
            return nights * package.base_price_per_night * guests

        if category in {"TREKKING", "JUNGLE_SAFARI"}:
            if package.base_price_per_person is None:
                raise PackageConfigError(
                    "base_price_per_person must be configured for trekking/safari packages."
                )
            return nights * package.base_price_per_person * guests

        raise PackageConfigError(f"Unsupported category for pricing: {category}")

    def _includes_weekend(self, booking_request: BookingRequest) -> bool:
        current = booking_request.start_date
        while current < booking_request.end_date:
            if current.weekday() >= 5:  # Saturday or Sunday
                return True
            current += timedelta(days=1)
        return False

    def _is_peak_season(self, booking_request: BookingRequest) -> bool:
        current = booking_request.start_date
        while current < booking_request.end_date:
            if current.month in self.PEAK_MONTHS:
                return True
            current += timedelta(days=1)
        return False
