"""SQLAlchemy transaction authority and request-session ownership."""

from __future__ import annotations

from collections.abc import Iterator
from typing import Any

from sqlalchemy import Engine, create_engine
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker

from .config import DatabaseWorkerSettings, ServerSettings
from .constants import DATABASE_POOL_PRE_PING, DATABASE_POOL_RECYCLE_SECONDS


class Base(DeclarativeBase):
    pass


def create_database_engine(
    settings: ServerSettings | DatabaseWorkerSettings,
    **overrides: Any,
) -> Engine:
    if not isinstance(settings, (ServerSettings, DatabaseWorkerSettings)):
        raise TypeError("settings must provide validated server or worker database settings")
    if not isinstance(overrides, dict):
        raise TypeError("overrides must be a dictionary")
    options: dict[str, Any] = {
        "pool_pre_ping": DATABASE_POOL_PRE_PING,
        "pool_recycle": DATABASE_POOL_RECYCLE_SECONDS,
    }
    options.update(overrides)
    return create_engine(settings.database_url, **options)


def create_session_factory(engine: Engine) -> sessionmaker[Session]:
    if not isinstance(engine, Engine):
        raise TypeError("engine must be a SQLAlchemy Engine")
    return sessionmaker(bind=engine, expire_on_commit=False, autoflush=False)


def session_dependency(factory: sessionmaker[Session]) -> Iterator[Session]:
    if not isinstance(factory, sessionmaker):
        raise TypeError("factory must be a SQLAlchemy sessionmaker")
    with factory() as session:
        yield session


__all__ = [
    "Base",
    "create_database_engine",
    "create_session_factory",
    "session_dependency",
]

