"""boundary/toml.py - establish trusted types at the TOML input boundary.

WHY:
    Functions here ESTABLISH input types rather than trust them. Parsed TOML
    arrives as opaque object / dict[str, Any]; isinstance(x, dict) narrows it to
    dict[Unknown, Unknown] under strict checking, reintroducing Unknown
    downstream. These guards assert the precise dict[str, object] /
    list[object] shapes the parser guarantees, so callers narrow once, here, and
    stay strict-clean.

OBS:
    Dependency-free leaf, sibling to utils/. utils/ holds helpers that TRUST
    their already-typed input; boundary/ holds primitives that ESTABLISH values
    from opaque external data. Both sit below pipeline/ and the stage packages,
    so importing them crosses none of the import-linter contracts.

OBS:
    Loaders narrow to dict[str, object] at the parse boundary so every consumer
    inherits a typed mapping and never sees Any. Nested access narrows stepwise
    (object is not subscriptable); see require_table for the one-call helper.
"""

from importlib.resources import files
from pathlib import Path
import tomllib
from typing import TypeIs  # TypeIs: Python 3.13+; on <=3.12 use typing_extensions


def is_list(value: object) -> TypeIs[list[object]]:
    """Narrow an opaque TOML value to a list (object elements)."""
    return isinstance(value, list)


def is_table(value: object) -> TypeIs[dict[str, object]]:
    """Narrow an opaque TOML value to a table (str keys, object values)."""
    return isinstance(value, dict)


def require_table(
    table: dict[str, object], key: str, context: str
) -> dict[str, object]:
    """Return a required nested table, narrowing object to dict[str, object]."""
    value = table.get(key)
    if not is_table(value):
        msg = f"{context} requires [{key}] to be a table"
        raise ValueError(msg)
    return value


def load_toml(path: Path) -> dict[str, object]:
    """Load TOML from a path, establishing dict[str, object] at the boundary."""
    data = tomllib.loads(path.read_text(encoding="utf-8"))
    if not is_table(data):
        msg = f"TOML root is not a table: {path}"
        raise ValueError(msg)
    return data


def load_manifest_schema() -> dict[str, object]:
    """Load manifest-schema.toml from se_manifest_schema."""
    schema_path = files("se_manifest_schema") / "manifest-schema.toml"
    with schema_path.open("rb") as f:
        data = tomllib.load(f)
    if not is_table(data):
        msg = "manifest-schema.toml root is not a table"
        raise ValueError(msg)
    return data


def load_reference_index(repo_dir: Path) -> dict[str, object]:
    """Load reference/index.toml from the repository root."""
    return load_toml(repo_dir / "reference" / "index.toml")
