#!/usr/bin/env python3
"""Regenerate PUBLIC_API.json from each module's live `__all__`.

The canonical source of public-API truth is each Python module's
`__all__` declaration. PUBLIC_API.json is the machine-readable
companion (DOC-08 / AP-10) that consumers / tooling / packagers
can diff to detect API additions and deletions across releases.
The two MUST stay in sync; drift in either direction is a defect
(CFM-03). `tests/conformance/test_public_api_pins.py` fails CI
when drift exists.

Usage:
    scripts/regenerate_public_api.py > PUBLIC_API.json
    # or, since the script is idempotent and prints to stdout:
    scripts/regenerate_public_api.py | diff - PUBLIC_API.json

The script imports the live modules — DO NOT run it before the
package is installed (e.g. `pip install -e .`).

How to add a new public name:
    1. Add the name to the source module's `__all__`.
    2. Run this script to regenerate PUBLIC_API.json.
    3. Update PUBLIC_API.md (human-readable) to describe the new
       name. (test_public_api_pins.py only checks the JSON
       against __all__; the .md is a separate human contract.)
"""

from __future__ import annotations

import importlib
import json
import sys

# The ordered list of modules that contribute to the public API.
# Top-level `mgf.hrb` is the consumer entry point; the rest are
# the supporting submodules consumers may legitimately import
# typed names from (e.g. `from mgf.hrb.exceptions import
# UnavailableError`). Order is documented stability: `mgf.hrb`
# first so a reader of the JSON sees the canonical surface first.
_PUBLIC_MODULES: list[str] = [
    "mgf.hrb",
    "mgf.hrb.config",
    "mgf.hrb.cli",
    "mgf.hrb.identity",
    "mgf.hrb.exceptions",
    "mgf.hrb.diagnostics",
    "mgf.hrb.domain",
    # PR-06 (presentation-layer standard) — the medium-agnostic
    # formatting helpers. Stdlib-only, no I/O, returns short strings.
    # Consumed by hrb-app/view/ + CLI + future TUI/web adapters.
    "mgf.hrb.fmt",
    # M-B B3 — typed builders for the subscription-predicate grammar.
    # Pure functions over dicts, stdlib-only; re-exported from
    # `mgf.hrb` so `from mgf.hrb import kind_in` is the normal path.
    "mgf.hrb.predicates",
    # SDK-07 (FEEDBACK) — I/O helper for `Snapshot`. Reads sysfs USB
    # attrs into a Snapshot ready for the comparator. Stdlib-only.
    "mgf.hrb.sysfs",
]

_SCHEMA_NOTE = (
    "Machine-readable companion to PUBLIC_API.md (DOC-08 / AP-10). "
    "Generated from __all__ at every release; pinned in CI by "
    "tests/conformance/test_public_api_pins.py against the live "
    "__all__. Keep both files in sync — drift in either direction "
    "is a defect (CFM-03)."
)


def build() -> dict[str, object]:
    """Walk the documented modules, collect each `__all__`, return
    the JSON-ready dict. Sorts every list so the output is
    deterministic (regen produces the same bytes for the same
    `__all__`)."""
    mgf_hrb = importlib.import_module("mgf.hrb")
    out: dict[str, object] = {
        "$schema_note": _SCHEMA_NOTE,
        "package": "mgf-hrb",
        "version": getattr(mgf_hrb, "__version__", "0.0.0"),
        "stability": "experimental",
        "modules": {},
    }
    for name in _PUBLIC_MODULES:
        try:
            mod = importlib.import_module(name)
        except ImportError as exc:
            print(
                f"WARNING: module {name!r} failed to import: {exc}",
                file=sys.stderr,
            )
            continue
        all_list = sorted(getattr(mod, "__all__", []))
        out["modules"][name] = {"all": all_list}  # type: ignore[index]
    return out


def main() -> int:
    """Emit the JSON to stdout. Returns 0 on success."""
    data = build()
    print(json.dumps(data, indent=2, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
