"""Pricing query specifications — Phase 10.4."""
from __future__ import annotations

from dataclasses import dataclass
from uuid import UUID

from sqlalchemy import Select, asc, desc, or_
from sqlalchemy.sql import ColumnElement

from app.models.pricing import CapabilityBundle, CapabilityDefinition, PricingRule
from app.models.types import CapabilityBundleStatus, CapabilityStatus, PricingRuleStatus

RULE_SORT = frozenset({"created_at", "updated_at", "code", "name", "status"})
CAP_SORT = frozenset({"created_at", "updated_at", "code", "name", "status"})
BUNDLE_SORT = frozenset({"created_at", "updated_at", "code", "name", "status"})


@dataclass(frozen=True, slots=True)
class PricingRuleListSpec:
    status: PricingRuleStatus | None = None
    organization_id: UUID | None = None
    q: str | None = None
    sort_by: str = "created_at"
    sort_dir: str = "desc"

    def filter_clauses(self) -> list[ColumnElement]:
        clauses: list[ColumnElement] = []
        if self.status is not None:
            clauses.append(PricingRule.status == self.status)
        if self.organization_id is not None:
            clauses.append(PricingRule.organization_id == self.organization_id)
        if self.q:
            term = f"%{self.q.strip()}%"
            clauses.append(
                or_(PricingRule.code.ilike(term), PricingRule.name.ilike(term))
            )
        return clauses

    def apply(self, stmt: Select) -> Select:
        clauses = self.filter_clauses()
        if clauses:
            stmt = stmt.where(*clauses)
        sort_key = self.sort_by if self.sort_by in RULE_SORT else "created_at"
        column = getattr(PricingRule, sort_key)
        order = desc(column) if self.sort_dir.lower() != "asc" else asc(column)
        return stmt.order_by(order)


@dataclass(frozen=True, slots=True)
class CapabilityListSpec:
    status: CapabilityStatus | None = None
    q: str | None = None
    sort_by: str = "created_at"
    sort_dir: str = "desc"

    def filter_clauses(self) -> list[ColumnElement]:
        clauses: list[ColumnElement] = []
        if self.status is not None:
            clauses.append(CapabilityDefinition.status == self.status)
        if self.q:
            term = f"%{self.q.strip()}%"
            clauses.append(
                or_(
                    CapabilityDefinition.code.ilike(term),
                    CapabilityDefinition.name.ilike(term),
                )
            )
        return clauses

    def apply(self, stmt: Select) -> Select:
        clauses = self.filter_clauses()
        if clauses:
            stmt = stmt.where(*clauses)
        sort_key = self.sort_by if self.sort_by in CAP_SORT else "created_at"
        column = getattr(CapabilityDefinition, sort_key)
        order = desc(column) if self.sort_dir.lower() != "asc" else asc(column)
        return stmt.order_by(order)


@dataclass(frozen=True, slots=True)
class BundleListSpec:
    status: CapabilityBundleStatus | None = None
    q: str | None = None
    sort_by: str = "created_at"
    sort_dir: str = "desc"

    def filter_clauses(self) -> list[ColumnElement]:
        clauses: list[ColumnElement] = []
        if self.status is not None:
            clauses.append(CapabilityBundle.status == self.status)
        if self.q:
            term = f"%{self.q.strip()}%"
            clauses.append(
                or_(
                    CapabilityBundle.code.ilike(term),
                    CapabilityBundle.name.ilike(term),
                )
            )
        return clauses

    def apply(self, stmt: Select) -> Select:
        clauses = self.filter_clauses()
        if clauses:
            stmt = stmt.where(*clauses)
        sort_key = self.sort_by if self.sort_by in BUNDLE_SORT else "created_at"
        column = getattr(CapabilityBundle, sort_key)
        order = desc(column) if self.sort_dir.lower() != "asc" else asc(column)
        return stmt.order_by(order)
