"""
Reservation business logic service.
"""
from datetime import date
from typing import Optional, List
from sqlalchemy.orm import Session

from app.models.reservation import Reservation, ReservationStatus
from app.models.room import Room


class ReservationService:
    """Service for reservation-related business logic."""

    def __init__(self, db: Session):
        self.db = db

    def check_availability(
        self,
        room_id: int,
        check_in_date: date,
        check_out_date: date,
        exclude_reservation_id: Optional[int] = None
    ) -> bool:
        """
        Check if a room is available for the given dates.

        Args:
            room_id: Room to check
            check_in_date: Check-in date
            check_out_date: Check-out date
            exclude_reservation_id: Reservation ID to exclude (for updates)

        Returns:
            True if room is available, False otherwise
        """
        query = self.db.query(Reservation).filter(
            Reservation.room_id == room_id,
            Reservation.status.in_([
                ReservationStatus.PENDING,
                ReservationStatus.CONFIRMED,
                ReservationStatus.CHECKED_IN
            ]),
            Reservation.check_in_date < check_out_date,
            Reservation.check_out_date > check_in_date
        )

        if exclude_reservation_id:
            query = query.filter(Reservation.id != exclude_reservation_id)

        conflicting = query.first()
        return conflicting is None

    def get_available_rooms(
        self,
        establishment_id: int,
        check_in_date: date,
        check_out_date: date,
        room_type_id: Optional[int] = None
    ) -> List[Room]:
        """
        Get all available rooms for given dates.

        Args:
            establishment_id: Establishment to search in
            check_in_date: Check-in date
            check_out_date: Check-out date
            room_type_id: Optional filter by room type

        Returns:
            List of available rooms
        """
        # Get all rooms
        room_query = self.db.query(Room).filter(
            Room.establishment_id == establishment_id,
            Room.is_active == True
        )

        if room_type_id:
            room_query = room_query.filter(Room.room_type_id == room_type_id)

        all_rooms = room_query.all()

        # Get rooms with conflicting reservations
        conflicting_query = self.db.query(Reservation.room_id).filter(
            Reservation.status.in_([
                ReservationStatus.PENDING,
                ReservationStatus.CONFIRMED,
                ReservationStatus.CHECKED_IN
            ]),
            Reservation.check_in_date < check_out_date,
            Reservation.check_out_date > check_in_date
        )

        conflicting_room_ids = {r.room_id for r in conflicting_query.all()}

        # Filter available rooms
        available_rooms = [
            room for room in all_rooms
            if room.id not in conflicting_room_ids
        ]

        return available_rooms

    def calculate_total_price(
        self,
        check_in_date: date,
        check_out_date: date,
        rate_per_night: float
    ) -> float:
        """
        Calculate total accommodation price.

        Args:
            check_in_date: Check-in date
            check_out_date: Check-out date
            rate_per_night: Nightly rate

        Returns:
            Total price
        """
        nights = (check_out_date - check_in_date).days
        return nights * rate_per_night

    def get_arrivals_count(
        self,
        establishment_id: int,
        target_date: date
    ) -> int:
        """Get count of arrivals for a date."""
        return self.db.query(Reservation).join(Room).filter(
            Room.establishment_id == establishment_id,
            Reservation.check_in_date == target_date,
            Reservation.status.in_([
                ReservationStatus.PENDING,
                ReservationStatus.CONFIRMED
            ])
        ).count()

    def get_departures_count(
        self,
        establishment_id: int,
        target_date: date
    ) -> int:
        """Get count of departures for a date."""
        return self.db.query(Reservation).join(Room).filter(
            Room.establishment_id == establishment_id,
            Reservation.check_out_date == target_date,
            Reservation.status == ReservationStatus.CHECKED_IN
        ).count()

    def get_in_house_count(
        self,
        establishment_id: int
    ) -> int:
        """Get count of currently checked-in guests."""
        from sqlalchemy import func

        result = self.db.query(
            func.sum(Reservation.adults + Reservation.children)
        ).join(Room).filter(
            Room.establishment_id == establishment_id,
            Reservation.status == ReservationStatus.CHECKED_IN
        ).scalar()

        return int(result) if result else 0
