import logging
from contextvars import ContextVar
from dataclasses import dataclass

from sqlalchemy.ext.asyncio import AsyncEngine
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlmodel.ext.asyncio.session import AsyncSession

from ..config import Settings
from ..config import get_settings
from .engine import get_database_url
from .engine import get_engine
from .session import get_session_factory

logger = logging.getLogger(__name__)


@dataclass(frozen=True)
class DatabaseRuntime:
    """Database runtime resources owned by app lifespan."""

    engine: AsyncEngine
    session_factory: async_sessionmaker[AsyncSession]


_runtime: ContextVar[DatabaseRuntime | None] = ContextVar("database_runtime", default=None)


async def dispose_database_runtime() -> None:
    """Dispose lifespan-owned async database resources."""
    runtime = _runtime.get()
    if runtime is None:
        return
    await runtime.engine.dispose()
    _runtime.set(None)


def initialize_database_runtime(*, settings: Settings | None = None) -> DatabaseRuntime:
    """Initialize lifespan-owned async DB resources once per process."""
    runtime = _runtime.get()
    if runtime is not None:
        return runtime

    active_settings = settings or get_settings()
    database_url = get_database_url(active_settings)
    engine = get_engine(database_url)
    session_factory = get_session_factory(database_url)
    runtime = DatabaseRuntime(engine=engine, session_factory=session_factory)
    _runtime.set(runtime)
    logger.debug("Initialized async database runtime for database_url=%s", engine.url)
    return runtime
