"""Settings repository.

Provides CRUD operations for the ``settings`` key-value table in the
application SQLite database.  All methods are plain async functions that
accept a :class:`aiosqlite.Connection` — no ORM, no HTTP exceptions.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    import aiosqlite


async def get_setting(db: aiosqlite.Connection, key: str) -> str | None:
    """Return the value for *key*, or ``None`` if it does not exist.

    Args:
        db: Active aiosqlite connection.
        key: The setting key to look up.

    Returns:
        The stored value string, or ``None`` if the key is absent.
    """
    async with db.execute(
        "SELECT value FROM settings WHERE key = ?",
        (key,),
    ) as cursor:
        row = await cursor.fetchone()
        return str(row[0]) if row is not None else None


async def set_setting(db: aiosqlite.Connection, key: str, value: str) -> None:
    """Insert or replace the setting identified by *key*.

    Args:
        db: Active aiosqlite connection.
        key: The setting key.
        value: The value to store.
    """
    await db.execute(
        "INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)",
        (key, value),
    )
    await db.commit()


async def delete_setting(db: aiosqlite.Connection, key: str) -> None:
    """Delete the setting identified by *key* if it exists.

    Args:
        db: Active aiosqlite connection.
        key: The setting key to remove.
    """
    await db.execute("DELETE FROM settings WHERE key = ?", (key,))
    await db.commit()


async def set_settings_batch(db: aiosqlite.Connection, settings: dict[str, str]) -> None:
    """Insert or replace multiple settings atomically in a single transaction.

    Wraps all writes in a single BEGIN IMMEDIATE ... COMMIT transaction to ensure
    atomicity. Either all settings are persisted or none are. This is useful for
    operations that must succeed as a logical unit (e.g., setup initialization).

    Args:
        db: Active aiosqlite connection.
        settings: A dictionary mapping setting keys to their values.

    Raises:
        Any exception from executing the SQL will cause a rollback.
    """
    if not settings:
        return

    try:
        await db.execute("BEGIN IMMEDIATE;")
        for key, value in settings.items():
            await db.execute(
                "INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)",
                (key, value),
            )
        await db.commit()
    except Exception:
        await db.rollback()
        raise


async def get_all_settings(db: aiosqlite.Connection) -> dict[str, str]:
    """Return all settings as a plain ``dict``.

    Args:
        db: Active aiosqlite connection.

    Returns:
        A dictionary mapping every stored key to its value.
    """
    async with db.execute("SELECT key, value FROM settings") as cursor:
        rows = await cursor.fetchall()
        return {str(row[0]): str(row[1]) for row in rows}
