"""Filtering, search and sorting specifications — Phase 11.9."""
from dataclasses import dataclass
from uuid import UUID

from sqlalchemy import asc, desc, or_

from app.models.integrations import (
    ExperienceConsumerConnectorDispatch,
    ExperienceConsumerConnectorRegistration,
    ExperienceNotifyDispatch,
    ExperienceWidgetDefinition,
    ExperienceWidgetInstance,
)

CONNECTOR_REGISTRATION_SORT = frozenset(
    {"created_at", "updated_at", "code", "name", "status", "kind"}
)
CONNECTOR_DISPATCH_SORT = frozenset(
    {"created_at", "updated_at", "status", "event_type", "direction"}
)
WIDGET_DEFINITION_SORT = frozenset(
    {"created_at", "updated_at", "code", "name", "status", "widget_kind"}
)
WIDGET_INSTANCE_SORT = frozenset(
    {"created_at", "updated_at", "code", "name", "status", "embed_ref"}
)
NOTIFY_DISPATCH_SORT = frozenset(
    {"created_at", "updated_at", "status", "channel", "template_key"}
)


@dataclass(frozen=True, slots=True)
class IntegrationListSpec:
    workspace_id: UUID | None = None
    site_id: UUID | None = None
    page_id: UUID | None = None
    status: str | None = None
    kind: str | None = None
    widget_kind: str | None = None
    registration_id: UUID | None = None
    q: str | None = None
    sort_by: str = "created_at"
    sort_dir: str = "desc"
    model = None
    sort_fields = frozenset()

    def filter_clauses(self):
        m = self.model
        clauses = []
        for field in (
            "workspace_id",
            "site_id",
            "page_id",
            "status",
            "kind",
            "widget_kind",
            "registration_id",
        ):
            value = getattr(self, field)
            if value is not None and hasattr(m, field):
                clauses.append(getattr(m, field) == value)
        if self.q:
            term = f"%{self.q.strip()}%"
            searchable = [
                getattr(m, name).ilike(term)
                for name in (
                    "code",
                    "name",
                    "description",
                    "event_type",
                    "embed_ref",
                    "template_key",
                    "channel",
                )
                if hasattr(m, name)
            ]
            if searchable:
                clauses.append(or_(*searchable))
        return clauses

    def apply(self, stmt):
        clauses = self.filter_clauses()
        if clauses:
            stmt = stmt.where(*clauses)
        key = self.sort_by if self.sort_by in self.sort_fields else "created_at"
        column = getattr(self.model, key)
        return stmt.order_by(asc(column) if self.sort_dir.lower() == "asc" else desc(column))


@dataclass(frozen=True, slots=True)
class ConsumerConnectorRegistrationListSpec(IntegrationListSpec):
    model = ExperienceConsumerConnectorRegistration
    sort_fields = CONNECTOR_REGISTRATION_SORT


@dataclass(frozen=True, slots=True)
class ConsumerConnectorDispatchListSpec(IntegrationListSpec):
    model = ExperienceConsumerConnectorDispatch
    sort_fields = CONNECTOR_DISPATCH_SORT


@dataclass(frozen=True, slots=True)
class WidgetDefinitionListSpec(IntegrationListSpec):
    model = ExperienceWidgetDefinition
    sort_fields = WIDGET_DEFINITION_SORT


@dataclass(frozen=True, slots=True)
class WidgetInstanceListSpec(IntegrationListSpec):
    model = ExperienceWidgetInstance
    sort_fields = WIDGET_INSTANCE_SORT


@dataclass(frozen=True, slots=True)
class NotifyDispatchListSpec(IntegrationListSpec):
    model = ExperienceNotifyDispatch
    sort_fields = NOTIFY_DISPATCH_SORT
