"""Routing repositories — Phase 10.6."""
from __future__ import annotations

from typing import Sequence
from uuid import UUID

from sqlalchemy import func, select

from app.models.routing import OptimizationRun, RoutePlan, RouteStop
from app.repositories.base import TenantBaseRepository
from app.specifications.routing import OptimizationRunListSpec, RoutePlanListSpec


class RoutePlanRepository(TenantBaseRepository[RoutePlan]):
    model = RoutePlan

    async def get_by_code(self, tenant_id: UUID, code: str) -> RoutePlan | 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: RoutePlanListSpec | None = None,
    ) -> Sequence[RoutePlan]:
        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: RoutePlanListSpec | 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 RouteStopRepository(TenantBaseRepository[RouteStop]):
    model = RouteStop

    async def list_for_plan(
        self, tenant_id: UUID, route_plan_id: UUID
    ) -> Sequence[RouteStop]:
        stmt = (
            select(self.model)
            .where(
                self.model.tenant_id == tenant_id,
                self.model.route_plan_id == route_plan_id,
                self.model.is_deleted.is_(False),
            )
            .order_by(self.model.sequence.asc())
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class OptimizationRunRepository(TenantBaseRepository[OptimizationRun]):
    model = OptimizationRun

    async def list_filtered(
        self,
        tenant_id: UUID,
        *,
        offset: int = 0,
        limit: int = 20,
        spec: OptimizationRunListSpec | None = None,
    ) -> Sequence[OptimizationRun]:
        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: OptimizationRunListSpec | 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())
