#!/usr/bin/python3
"""Assemble zshmodules summary/body includes from module fragment rST files.

Canonical module order is owned by the Makefile (sphinx.mk MOD_DOCS), which
passes fragment paths on the command line. This tool does not discover or
sort modules.
"""
import argparse
import re
import sys
from pathlib import Path


_META_RE = re.compile(
    r"^\.\. zsh-module-meta::\s*\n"
    r"\s*:name:\s+(.*?)\n"
    r"\s*:summary:\s+(.*?)\n",
    re.MULTILINE,
)


def parse_rst_mod_header(rst_file_path: Path):
    """Return (name, summary) from ``.. zsh-module-meta::`` at file start."""
    content = rst_file_path.read_text(encoding="utf-8")
    meta_match = _META_RE.search(content)
    if not meta_match:
        return None, None
    name = meta_match.group(1).strip()
    summary = re.sub(r"\s+", " ", meta_match.group(2).strip())
    return name, summary


def generate_module_files(source_dir: Path, output_dir: Path, fragments):
    """Emit modules_summary.rst.inc and modules_body.rst.inc in argument order."""
    source_dir = source_dir.resolve()
    output_dir = output_dir.resolve()
    output_dir.mkdir(parents=True, exist_ok=True)

    modules = []
    for frag in fragments:
        rst_file = Path(frag)
        if not rst_file.is_file():
            print(f"error: missing module fragment: {rst_file}", file=sys.stderr)
            sys.exit(1)
        name, summary = parse_rst_mod_header(rst_file)
        if not name or not summary:
            print(
                f"error: missing or incomplete zsh-module-meta in {rst_file}",
                file=sys.stderr,
            )
            sys.exit(1)
        try:
            rel = rst_file.resolve().relative_to(source_dir)
        except ValueError:
            print(
                f"error: fragment not under source dir {source_dir}: {rst_file}",
                file=sys.stderr,
            )
            sys.exit(1)
        modules.append(
            {
                "name": name,
                "summary": summary,
                "include": rel.as_posix(),
            }
        )

    summary_lines = []
    for mod in modules:
        title = f"The {mod['name']} Module"
        summary_lines.append(f":ref:`{title}`")
        summary_lines.append(f"  {mod['summary']}")
        summary_lines.append("")

    body_lines = []
    for mod in modules:
        title = f"The {mod['name']} Module"
        # Explicit labels: titles with '/' (e.g. zsh/net/tcp) do not get
        # reliable name-based :ref: targets from the section heading alone.
        body_lines.append(f".. _{title}:")
        body_lines.append("")
        body_lines.append(title)
        body_lines.append("-" * len(title))
        body_lines.append("")
        body_lines.append(f".. include:: /{mod['include']}")
        body_lines.append("")

    (output_dir / "modules_summary.rst.inc").write_text(
        "\n".join(summary_lines) + ("\n" if summary_lines else ""),
        encoding="utf-8",
    )
    (output_dir / "modules_body.rst.inc").write_text(
        "\n".join(body_lines) + ("\n" if body_lines else ""),
        encoding="utf-8",
    )

    print(f"Generated module snippets for {len(modules)} modules in {output_dir}")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description=(
            "Generate modules_summary.rst.inc and modules_body.rst.inc "
            "from ordered module fragment rST files."
        )
    )
    parser.add_argument(
        "source_dir",
        help="Sphinx source root (used for relative include paths).",
    )
    parser.add_argument(
        "output_dir",
        help="Directory to write the .rst.inc snippet files.",
    )
    parser.add_argument(
        "fragments",
        nargs="+",
        help="Module fragment .rst paths in canonical Makefile order.",
    )
    args = parser.parse_args()
    generate_module_files(
        Path(args.source_dir),
        Path(args.output_dir),
        args.fragments,
    )
