"""Generate `COMMANDS.md` from the slash-command registry.

Usage:
    python scripts/generate_commands_catalog.py           # writes COMMANDS.md
    python scripts/generate_commands_catalog.py --check   # exits 1 if stale
"""

from __future__ import annotations

import argparse
import difflib
import sys
from pathlib import Path

_CODE_DIR = Path(__file__).resolve().parents[1]
"""Root of the deepagents-code package (libs/code/)."""

sys.path.insert(0, str(_CODE_DIR))

from deepagents_code.command_registry import (  # noqa: E402
    COMMANDS,
    HIDDEN_COMMANDS,
)

_OUTPUT = _CODE_DIR / "COMMANDS.md"
"""Generated output file. Lives outside `deepagents_code/` so it is not shipped."""

_HEADER = """\
<!-- AUTO-GENERATED by scripts/generate_commands_catalog.py — do not edit manually. -->
# Slash command catalog

This is the generated reference for `deepagents-code` slash commands. Command
names, aliases, and descriptions come from `deepagents_code/command_registry.py`.
Regenerate this file with `make commands-catalog` after changing command names,
aliases, descriptions, visibility, or hidden-command metadata.
"""


def _fmt_cell(text: str) -> str:
    """Escape pipes so cell content is table-safe.

    Returns:
        The text with `|` characters escaped, or an empty string if `text` is falsy.
    """
    return text.replace("|", "\\|") if text else ""


def generate() -> str:
    """Return the full markdown content for `COMMANDS.md`."""
    lines: list[str] = [_HEADER, ""]

    public = sorted(COMMANDS, key=lambda c: c.name)
    lines.extend(
        [
            f"## Public ({len(public)})\n",
            "| Command | Aliases | Description |",
            "| --- | --- | --- |",
        ]
    )
    for cmd in public:
        aliases = ", ".join(f"`{a}`" for a in cmd.aliases) if cmd.aliases else ""
        lines.append(
            "| "
            + " | ".join(
                _fmt_cell(c) for c in (f"`{cmd.name}`", aliases, cmd.description)
            )
            + " |"
        )
    lines.append("")

    hidden = sorted(HIDDEN_COMMANDS)
    lines.extend(
        [
            f"## Hidden ({len(hidden)})\n",
            (
                "These commands are intentionally omitted from autocomplete and help. "
                "See the `HIDDEN_COMMANDS` docstring in the registry for context.\n"
            ),
        ]
    )
    lines.extend(f"- `{name}`" for name in hidden)
    lines.append("")

    return "\n".join(lines)


def main() -> None:
    """Entry point.

    Raises:
        SystemExit: When `--check` is passed and `COMMANDS.md` is missing or stale.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--check",
        action="store_true",
        help="Check that COMMANDS.md is up-to-date (exit 1 if stale).",
    )
    args = parser.parse_args()

    expected = generate()

    if args.check:
        if not _OUTPUT.exists():
            print(f"MISSING: {_OUTPUT}", file=sys.stderr)
            print(
                "Run `make commands-catalog` from libs/code/ to regenerate.",
                file=sys.stderr,
            )
            raise SystemExit(1)
        actual = _OUTPUT.read_text(encoding="utf-8")
        if actual != expected:
            diff = difflib.unified_diff(
                actual.splitlines(),
                expected.splitlines(),
                fromfile="COMMANDS.md (on disk)",
                tofile="COMMANDS.md (expected)",
                lineterm="",
            )
            print(f"STALE: {_OUTPUT}\n", file=sys.stderr)
            print("\n".join(diff), file=sys.stderr)
            print(
                "\nRun `make commands-catalog` from libs/code/ to regenerate.",
                file=sys.stderr,
            )
            raise SystemExit(1)
        print(f"OK: {_OUTPUT} is up-to-date")
    else:
        _OUTPUT.write_text(expected, encoding="utf-8")
        print(f"Wrote {_OUTPUT}")


if __name__ == "__main__":
    main()
