"""Configuration objects for auen CRUD routers."""

from __future__ import annotations

import enum
from collections.abc import Awaitable, Callable, Sequence

from pydantic import BaseModel, Field
from pydantic.dataclasses import dataclass

from auen.types import User


class Operation(enum.Enum):
    """CRUD operations that can be enabled/disabled."""

    CREATE = "create"
    LIST = "list"
    READ = "read"
    UPDATE = "update"
    DELETE = "delete"
    BULK_CREATE = "bulk_create"
    BULK_UPDATE = "bulk_update"
    BULK_DELETE = "bulk_delete"


ALL_OPERATIONS: frozenset[Operation] = frozenset(Operation)


@dataclass(frozen=True)
class SchemaConfig:
    """Schemas used for request/response bodies.

    All three must be provided. Use ``derive_schemas`` to
    auto-generate them from the table model.
    """

    create: type[BaseModel]
    read: type[BaseModel]
    update: type[BaseModel]


@dataclass(frozen=True)
class AuthConfig:
    """Authentication/authorization configuration.

    ``dependency`` is a FastAPI dependency callable that returns
    the current user or raises HTTP 401.
    """

    dependency: Callable[..., User]
    mode: str = "depends"  # "depends" | "security"
    scopes_by_operation: dict[Operation, list[str]] = Field(default_factory=dict)
    allow_anonymous: set[Operation] = Field(default_factory=set)


@dataclass(frozen=True)
class PaginationConfig:
    """Pagination settings for LIST endpoints."""

    default_limit: int = 50
    max_limit: int = 200
    style: str = "limit_offset"
    include_total: bool = False


@dataclass(frozen=True)
class FilterFieldConfig:
    """Allowed filter operations for a single field."""

    ops: frozenset[str] = frozenset({"eq"})


@dataclass(frozen=True)
class FilterConfig:
    """Filtering and sorting configuration for LIST."""

    fields: dict[str, FilterFieldConfig] = Field(default_factory=dict)
    sort_fields: Sequence[str] = ()


# Event hook type: async callable receiving (session, obj, user)
EventHook = Callable[..., Awaitable[None]]


@dataclass(frozen=True)
class HooksConfig:
    """Lifecycle hooks for CRUD operations.

    Each hook is an async callable invoked at the appropriate point.
    Before-hooks can raise exceptions to abort the operation.
    After-hooks are called after the DB commit.

    All hooks receive ``(session, obj, user)`` where ``obj`` is the
    input data (before) or the DB object (after).
    """

    before_create: EventHook | None = None
    after_create: EventHook | None = None
    before_update: EventHook | None = None
    after_update: EventHook | None = None
    before_delete: EventHook | None = None
    after_delete: EventHook | None = None


@dataclass(frozen=True)
class SoftDeleteConfig:
    """Soft delete configuration.

    When enabled, DELETE sets a timestamp column instead of removing the row.
    All queries automatically exclude soft-deleted rows.
    """

    field: str = "deleted_at"
    """Name of the datetime column used for soft delete."""
