"""Shared typing primitives for auen."""

from __future__ import annotations

import enum
from collections.abc import AsyncGenerator, Collection
from datetime import date, datetime
from decimal import Decimal
from types import EllipsisType, GenericAlias, UnionType
from typing import Protocol, TypeAlias, TypedDict, TypeVar
from uuid import UUID

from pydantic import BaseModel
from pydantic_core import PydanticUndefinedType
from sqlmodel import SQLModel
from sqlmodel.ext.asyncio.session import AsyncSession
from sqlmodel.sql.expression import SelectOfScalar


class User(Protocol):
    """Opaque user type for auth/policy hooks."""


TModel = TypeVar("TModel", bound=SQLModel, covariant=True)

PKValue: TypeAlias = int | str | UUID
PKType: TypeAlias = type[int] | type[str] | type[UUID]
SelectQuery: TypeAlias = SelectOfScalar[TModel]
SessionDep: TypeAlias = AsyncGenerator[AsyncSession, None]

FilterScalar: TypeAlias = (
    int | float | str | bool | UUID | date | datetime | Decimal | enum.Enum
)
FilterValue: TypeAlias = FilterScalar | Collection[FilterScalar]
FilterParamValue: TypeAlias = FilterValue | None
FilterParams: TypeAlias = dict[str, FilterParamValue]
ModelFieldAnnotation: TypeAlias = type | GenericAlias | UnionType | None

ResponseModel: TypeAlias = type[BaseModel] | GenericAlias

FieldDefault: TypeAlias = (
    EllipsisType
    | None
    | int
    | str
    | float
    | bool
    | date
    | datetime
    | UUID
    | Decimal
    | enum.Enum
    | PydanticUndefinedType
)
ModelFieldDefinition: TypeAlias = tuple[type, FieldDefault]


class PageEnvelope(TypedDict):
    items: list[SQLModel]
    total: int
    limit: int
    offset: int


ListResponse: TypeAlias = list[SQLModel] | PageEnvelope
