"""Dispatch repositories — Phase 10.5."""
from __future__ import annotations

from typing import Sequence
from uuid import UUID

from sqlalchemy import func, select

from app.models.dispatch import DispatchJob, JobAssignment
from app.repositories.base import TenantBaseRepository
from app.specifications.dispatch import DispatchJobListSpec, JobAssignmentListSpec


class DispatchJobRepository(TenantBaseRepository[DispatchJob]):
    model = DispatchJob

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

    async def list_filtered(
        self,
        tenant_id: UUID,
        *,
        offset: int = 0,
        limit: int = 20,
        spec: DispatchJobListSpec | None = None,
    ) -> Sequence[DispatchJob]:
        stmt = select(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.is_deleted.is_(False),
        )
        if spec is not None:
            stmt = spec.apply(stmt)
        else:
            stmt = stmt.order_by(self.model.created_at.desc())
        stmt = stmt.offset(offset).limit(limit)
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count_filtered(
        self, tenant_id: UUID, *, spec: DispatchJobListSpec | None = None
    ) -> int:
        stmt = select(func.count()).select_from(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.is_deleted.is_(False),
        )
        if spec is not None:
            clauses = spec.filter_clauses()
            if clauses:
                stmt = stmt.where(*clauses)
        result = await self.session.execute(stmt)
        return int(result.scalar_one())


class JobAssignmentRepository(TenantBaseRepository[JobAssignment]):
    model = JobAssignment

    async def list_filtered(
        self,
        tenant_id: UUID,
        *,
        offset: int = 0,
        limit: int = 20,
        spec: JobAssignmentListSpec | None = None,
    ) -> Sequence[JobAssignment]:
        stmt = select(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.is_deleted.is_(False),
        )
        if spec is not None:
            stmt = spec.apply(stmt)
        else:
            stmt = stmt.order_by(self.model.created_at.desc())
        stmt = stmt.offset(offset).limit(limit)
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count_filtered(
        self, tenant_id: UUID, *, spec: JobAssignmentListSpec | None = None
    ) -> int:
        stmt = select(func.count()).select_from(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.is_deleted.is_(False),
        )
        if spec is not None:
            clauses = spec.filter_clauses()
            if clauses:
                stmt = stmt.where(*clauses)
        result = await self.session.execute(stmt)
        return int(result.scalar_one())

    async def list_for_job(
        self, tenant_id: UUID, dispatch_job_id: UUID
    ) -> Sequence[JobAssignment]:
        stmt = select(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.dispatch_job_id == dispatch_job_id,
            self.model.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()
