"""Doctor panel repositories — Phase 13.2."""
from __future__ import annotations

from datetime import datetime, timezone
from uuid import UUID

from sqlalchemy import and_, func, select

from app.models.doctor_panel import VisitNote, VisitSession
from app.models.types import VisitSessionStatus
from app.repositories.base import TenantBaseRepository
from app.specifications.doctor_panel import VisitSessionListSpec


class VisitSessionRepository(TenantBaseRepository[VisitSession]):
    model = VisitSession

    async def get_by_code(self, tenant_id: UUID, code: str) -> VisitSession | None:
        stmt = select(VisitSession).where(
            VisitSession.tenant_id == tenant_id,
            VisitSession.code == code,
            VisitSession.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def get_by_appointment(
        self, tenant_id: UUID, appointment_id: UUID
    ) -> VisitSession | None:
        stmt = select(VisitSession).where(
            VisitSession.tenant_id == tenant_id,
            VisitSession.appointment_id == appointment_id,
            VisitSession.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    def _filter_clauses(self, tenant_id: UUID, spec: VisitSessionListSpec | None):
        clauses = [VisitSession.tenant_id == tenant_id, VisitSession.is_deleted.is_(False)]
        if spec is None:
            return clauses
        if spec.doctor_id is not None:
            clauses.append(VisitSession.doctor_id == spec.doctor_id)
        if spec.clinic_id is not None:
            clauses.append(VisitSession.clinic_id == spec.clinic_id)
        if spec.status is not None:
            clauses.append(VisitSession.status == spec.status)
        return clauses

    async def list_filtered(
        self,
        tenant_id: UUID,
        *,
        offset: int = 0,
        limit: int = 20,
        spec: VisitSessionListSpec | None = None,
    ):
        clauses = self._filter_clauses(tenant_id, spec)
        sort_col = getattr(
            VisitSession,
            spec.sort_by if spec else "queue_position",
            VisitSession.queue_position,
        )
        order = sort_col.asc() if spec and spec.sort_dir == "asc" else sort_col.desc()
        stmt = (
            select(VisitSession)
            .where(and_(*clauses))
            .order_by(order)
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count_by_status(
        self, tenant_id: UUID, *, doctor_id: UUID, status: VisitSessionStatus
    ) -> int:
        stmt = select(func.count()).select_from(VisitSession).where(
            VisitSession.tenant_id == tenant_id,
            VisitSession.doctor_id == doctor_id,
            VisitSession.status == status,
            VisitSession.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return int(result.scalar_one())

    async def count_completed_today(self, tenant_id: UUID, *, doctor_id: UUID) -> int:
        today = datetime.now(timezone.utc).date()
        stmt = select(func.count()).select_from(VisitSession).where(
            VisitSession.tenant_id == tenant_id,
            VisitSession.doctor_id == doctor_id,
            VisitSession.status == VisitSessionStatus.COMPLETED,
            VisitSession.is_deleted.is_(False),
            func.date(VisitSession.finished_at) == today,
        )
        result = await self.session.execute(stmt)
        return int(result.scalar_one())


class VisitNoteRepository(TenantBaseRepository[VisitNote]):
    model = VisitNote

    async def get_by_code(self, tenant_id: UUID, code: str) -> VisitNote | None:
        stmt = select(VisitNote).where(
            VisitNote.tenant_id == tenant_id,
            VisitNote.code == code,
            VisitNote.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def list_by_session(self, tenant_id: UUID, visit_session_id: UUID):
        stmt = select(VisitNote).where(
            VisitNote.tenant_id == tenant_id,
            VisitNote.visit_session_id == visit_session_id,
            VisitNote.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()
