"""
Databaselag for TeeCup.

Det kritiske her er hvordan organisasjonskonteksten (`app.current_org`) settes:

  * Den settes med set_config(..., is_local => true), dvs. SET LOCAL — verdien
    gjelder KUN inne i den aktive transaksjonen og nullstilles automatisk når
    transaksjonen avsluttes.
  * Uten dette (en vanlig SET på en pool-tilkobling) ville konteksten blitt
    liggende på tilkoblingen når den returneres til poolen, og neste forespørsel
    — potensielt en ANNEN organisasjon — ville arvet den. Det ville brutt
    isolasjonen ved gjenbruk av tilkoblinger.

Hver forespørsel som rører organisasjonsdata kjører altså i én transaksjon med
org-konteksten satt lokalt.
"""

from contextlib import asynccontextmanager
from typing import AsyncIterator

import asyncpg

from .config import settings

_pool: asyncpg.Pool | None = None


async def init_pool() -> None:
    global _pool
    _pool = await asyncpg.create_pool(
        host=settings.DB_HOST,
        port=settings.DB_PORT,
        user=settings.DB_USER,
        password=settings.DB_PASS,
        database=settings.DB_NAME,
        min_size=settings.DB_POOL_MIN,
        max_size=settings.DB_POOL_MAX,
    )


async def close_pool() -> None:
    global _pool
    if _pool is not None:
        await _pool.close()
        _pool = None


def _require_pool() -> asyncpg.Pool:
    if _pool is None:
        raise RuntimeError("DB-poolen er ikke initialisert (kall init_pool ved oppstart).")
    return _pool


@asynccontextmanager
async def plain_connection() -> AsyncIterator[asyncpg.Connection]:
    """Tilkobling UTEN org-kontekst.

    Brukes kun til auth-laget (f.eks. oppslag i organization_membership, som
    ikke er organisasjonsavgrenset). Rør aldri organisasjonsdata her.
    """
    pool = _require_pool()
    async with pool.acquire() as conn:
        yield conn


@asynccontextmanager
async def org_connection(organization_id: str) -> AsyncIterator[asyncpg.Connection]:
    """Tilkobling med org-kontekst satt lokalt for én transaksjon.

    All lesing/skriving av organisasjonsdata skal gå gjennom denne. RLS filtrerer
    da automatisk på organization_id = app.current_org.

    VIKTIG: `organization_id` MÅ på forhånd være verifisert mot brukerens
    medlemskap (se auth.get_authorized_org). Denne funksjonen stoler på at
    verdien allerede er autorisert.
    """
    pool = _require_pool()
    async with pool.acquire() as conn:
        async with conn.transaction():
            # SET LOCAL via set_config(..., true): nullstilles ved transaksjonsslutt.
            await conn.execute(
                "SELECT set_config('app.current_org', $1, true)",
                str(organization_id),
            )
            yield conn
