"""Pin: ``PUBLIC_API.md`` MUST list every public name in ``__all__``.

Rule **AP-10** — the public-API document is the contract list. It
MUST stay in sync with ``__all__`` of every public package, OR the
contract drifts: a public name nobody documented becomes "you
should not have depended on that".

The check is deliberately substring-based against the ``PUBLIC_API.md``
text rather than a structured parser — it tolerates wording
changes around the name (signature shape, type hints, prose) but
fails loudly if a name disappears from the doc entirely.
"""

from __future__ import annotations

from pathlib import Path

import pytest

import mgf.common
import mgf.common.cli
import mgf.common.config
import mgf.common.exceptions
import mgf.common.observability
import mgf.common.progress
import mgf.common.progress.asyncio
import mgf.common.registry
import mgf.common.settings
import mgf.common.typing
import mgf.common.vault

PUBLIC_API_PATH = Path(__file__).resolve().parent.parent.parent / "PUBLIC_API.md"


def _public_names() -> list[tuple[str, str]]:
    """Yield every (module_label, name) for the project's public surface."""
    out: list[tuple[str, str]] = []
    for module in (
        mgf.common,
        mgf.common.exceptions,
        mgf.common.config,
        mgf.common.observability,
        mgf.common.settings,
        mgf.common.typing,
        mgf.common.progress,
        mgf.common.progress.asyncio,
        mgf.common.vault,
        mgf.common.cli,
        mgf.common.registry,
    ):
        for name in module.__all__:
            out.append((module.__name__, name))
    out.append(("mgf.common", "__version__"))
    return out


@pytest.mark.parametrize("module_label,name", _public_names())
def test_public_name_appears_in_public_api_doc(module_label: str, name: str) -> None:
    """Every name in ``__all__`` MUST appear in PUBLIC_API.md."""
    text = PUBLIC_API_PATH.read_text()
    # The doc renders names in backticks (e.g., `configure(...)` or
    # bare `AppError`). Match on the bare name with backtick prefix
    # so we don't false-positive on prose that happens to contain
    # the word.
    needle = f"`{name}"
    assert needle in text, (
        f"AP-10: {module_label}.{name!r} is in __all__ but does not "
        f"appear in PUBLIC_API.md. Add a row in the section for "
        f"{module_label!r} with stability tier + one-line description, "
        f"or remove the name from __all__."
    )


def test_public_api_doc_exists_and_is_non_empty() -> None:
    """Sanity: the doc exists and has content."""
    assert PUBLIC_API_PATH.exists(), f"AP-10: PUBLIC_API.md missing at {PUBLIC_API_PATH}"
    assert PUBLIC_API_PATH.stat().st_size > 1000, (
        f"AP-10: PUBLIC_API.md exists but is suspiciously small "
        f"({PUBLIC_API_PATH.stat().st_size} bytes)"
    )
