"""Scheduling & Booking repositories — Phase 9.4."""
from __future__ import annotations

from datetime import datetime
from uuid import UUID

from sqlalchemy import func, select

from app.models.booking import Booking, Equipment, ResourceReservation, SportsSession, WaitingListEntry
from app.models.types import BookingStatus, LifecycleStatus
from app.repositories.base import TenantBaseRepository


class EquipmentRepository(TenantBaseRepository[Equipment]):
    model = Equipment


class SportsSessionRepository(TenantBaseRepository[SportsSession]):
    model = SportsSession

    async def list_by_center(
        self, tenant_id: UUID, sports_center_id: UUID, *, offset: int = 0, limit: int = 20
    ):
        stmt = (
            select(self.model)
            .where(
                self.model.tenant_id == tenant_id,
                self.model.sports_center_id == sports_center_id,
                self.model.is_deleted.is_(False),
            )
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count_conflicts(
        self,
        tenant_id: UUID,
        sports_center_id: UUID,
        starts_at: datetime,
        ends_at: datetime,
        *,
        coach_id: UUID | None = None,
        facility_id: UUID | None = None,
        exclude_id: UUID | None = None,
    ) -> int:
        clauses = [
            self.model.tenant_id == tenant_id,
            self.model.sports_center_id == sports_center_id,
            self.model.is_deleted.is_(False),
            self.model.status == LifecycleStatus.ACTIVE,
            self.model.starts_at < ends_at,
            self.model.ends_at > starts_at,
        ]
        if coach_id:
            clauses.append(self.model.coach_id == coach_id)
        if facility_id:
            clauses.append(self.model.facility_id == facility_id)
        if exclude_id:
            clauses.append(self.model.id != exclude_id)
        stmt = select(func.count()).select_from(self.model).where(*clauses)
        return (await self.session.execute(stmt)).scalar_one()


class BookingRepository(TenantBaseRepository[Booking]):
    model = Booking

    async def count_active_for_session(self, tenant_id: UUID, session_id: UUID) -> int:
        stmt = select(func.count()).select_from(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.session_id == session_id,
            self.model.is_deleted.is_(False),
            self.model.status.in_([BookingStatus.PENDING, BookingStatus.CONFIRMED]),
        )
        return (await self.session.execute(stmt)).scalar_one()


class WaitingListEntryRepository(TenantBaseRepository[WaitingListEntry]):
    model = WaitingListEntry

    async def next_position(self, tenant_id: UUID, session_id: UUID) -> int:
        stmt = select(func.max(self.model.position)).where(
            self.model.tenant_id == tenant_id,
            self.model.session_id == session_id,
            self.model.is_deleted.is_(False),
        )
        current = (await self.session.execute(stmt)).scalar_one_or_none()
        return (current or 0) + 1


class ResourceReservationRepository(TenantBaseRepository[ResourceReservation]):
    model = ResourceReservation

    async def count_conflicts(
        self,
        tenant_id: UUID,
        starts_at: datetime,
        ends_at: datetime,
        *,
        facility_id: UUID | None = None,
        equipment_id: UUID | None = None,
        exclude_id: UUID | None = None,
    ) -> int:
        clauses = [
            self.model.tenant_id == tenant_id,
            self.model.is_deleted.is_(False),
            self.model.status.in_([BookingStatus.PENDING, BookingStatus.CONFIRMED]),
            self.model.starts_at < ends_at,
            self.model.ends_at > starts_at,
        ]
        if facility_id:
            clauses.append(self.model.facility_id == facility_id)
        if equipment_id:
            clauses.append(self.model.equipment_id == equipment_id)
        if exclude_id:
            clauses.append(self.model.id != exclude_id)
        stmt = select(func.count()).select_from(self.model).where(*clauses)
        return (await self.session.execute(stmt)).scalar_one()
