"""Fleet repositories — Phase 10.2."""
from __future__ import annotations

from typing import Sequence
from uuid import UUID

from sqlalchemy import func, select

from app.models.fleet import Fleet, Vehicle, VehicleAssignment, VehicleType
from app.models.types import VehicleAssignmentStatus
from app.repositories.base import TenantBaseRepository
from app.specifications.fleet import FleetListSpec, VehicleListSpec, VehicleTypeListSpec


class FleetRepository(TenantBaseRepository[Fleet]):
    model = Fleet

    async def get_by_code(self, tenant_id: UUID, code: str) -> Fleet | 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: FleetListSpec | None = None,
    ) -> Sequence[Fleet]:
        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: FleetListSpec | 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 VehicleTypeRepository(TenantBaseRepository[VehicleType]):
    model = VehicleType

    async def get_by_code(self, tenant_id: UUID, code: str) -> VehicleType | 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: VehicleTypeListSpec | None = None,
    ) -> Sequence[VehicleType]:
        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: VehicleTypeListSpec | 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 VehicleRepository(TenantBaseRepository[Vehicle]):
    model = Vehicle

    async def get_by_code(self, tenant_id: UUID, code: str) -> Vehicle | 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: VehicleListSpec | None = None,
    ) -> Sequence[Vehicle]:
        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: VehicleListSpec | 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 VehicleAssignmentRepository(TenantBaseRepository[VehicleAssignment]):
    model = VehicleAssignment

    async def list_for_vehicle(
        self, tenant_id: UUID, vehicle_id: UUID
    ) -> Sequence[VehicleAssignment]:
        stmt = (
            select(self.model)
            .where(
                self.model.tenant_id == tenant_id,
                self.model.vehicle_id == vehicle_id,
                self.model.is_deleted.is_(False),
            )
            .order_by(self.model.created_at.desc())
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def get_active_for_vehicle(
        self, tenant_id: UUID, vehicle_id: UUID
    ) -> VehicleAssignment | None:
        stmt = select(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.vehicle_id == vehicle_id,
            self.model.status == VehicleAssignmentStatus.ACTIVE,
            self.model.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()
