"""Pricing repositories — Phase 10.4."""
from __future__ import annotations

from typing import Sequence
from uuid import UUID

from sqlalchemy import func, select

from app.models.pricing import CapabilityBundle, CapabilityDefinition, PricingRule
from app.repositories.base import TenantBaseRepository
from app.specifications.pricing import (
    BundleListSpec,
    CapabilityListSpec,
    PricingRuleListSpec,
)


class PricingRuleRepository(TenantBaseRepository[PricingRule]):
    model = PricingRule

    async def get_by_code(self, tenant_id: UUID, code: str) -> PricingRule | 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: PricingRuleListSpec | None = None,
    ) -> Sequence[PricingRule]:
        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: PricingRuleListSpec | 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 CapabilityDefinitionRepository(TenantBaseRepository[CapabilityDefinition]):
    model = CapabilityDefinition

    async def get_by_code(
        self, tenant_id: UUID, code: str
    ) -> CapabilityDefinition | 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: CapabilityListSpec | None = None,
    ) -> Sequence[CapabilityDefinition]:
        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: CapabilityListSpec | 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 CapabilityBundleRepository(TenantBaseRepository[CapabilityBundle]):
    model = CapabilityBundle

    async def get_by_code(self, tenant_id: UUID, code: str) -> CapabilityBundle | 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: BundleListSpec | None = None,
    ) -> Sequence[CapabilityBundle]:
        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: BundleListSpec | 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())
