import asyncio
from abc import ABC
from collections.abc import Sequence
from contextlib import asynccontextmanager

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

from ..config import Settings
from ..config import get_settings
from ..db.session import resolve_session_factory
from ..db.session import session_scope


class ServiceBase(ABC):
    """Thin service class for managing documents in the database."""

    settings: Settings
    session_factory: async_sessionmaker[AsyncSession]
    queue: asyncio.Queue

    def __init__(
        self,
        session_factory: async_sessionmaker[AsyncSession] | None = None,
        queue: asyncio.Queue | None = None,
    ):
        self.settings = get_settings()
        self.session_factory = session_factory or resolve_session_factory()
        self.queue = queue or asyncio.Queue()

    @asynccontextmanager
    async def _session_scope(self, session: AsyncSession | None = None):
        """Provide a transactional scope around a series of operations."""
        async with session_scope(
            session_factory=self.session_factory,
            session=session,
        ) as active_session:
            yield active_session

    async def _finalize(
        self,
        *,
        session: AsyncSession,
        caller_session: AsyncSession | None,
        refresh: Sequence[object] = (),
    ) -> None:
        """Finalize a write based on transaction ownership.

        Service-owned sessions commit immediately. Caller-owned sessions flush so
        orchestration code can commit once at a larger transaction boundary.
        """
        should_commit = caller_session is None
        if should_commit:
            await session.commit()
        else:
            await session.flush()

        for obj in refresh:
            await session.refresh(obj)
