#!/usr/bin/python3
"""Emit an ordered rST include bundle from fragment paths.

Canonical fragment order is owned by the Makefile (sphinx.mk), which passes
paths on the command line. This tool does not discover or sort fragments.

With --demote-top-title, fragment bodies are inlined and each file's first
top-level (====) title is demoted to ---- so the bundle can sit under a
shell document title without dropping chapter headings in man output.
"""
import argparse
import re
import sys
from pathlib import Path

_TOP_TITLE_RE = re.compile(
    r"^(?P<title>.+)\n(?P<under>=[=\s]*)$",
    re.MULTILINE,
)


def _demote_top_title(text: str) -> str:
    """Demote the first ==== title underline to ----."""
    match = _TOP_TITLE_RE.search(text)
    if not match:
        return text
    under = match.group("under")
    if not under.strip().startswith("="):
        return text
    demoted = "-" * len(under.rstrip()) + ("\n" if under.endswith("\n") else "")
    return text[: match.start("under")] + demoted + text[match.end("under") :]


def write_bundle(
    source_dir: Path,
    output_dir: Path,
    out_basename: str,
    fragments,
    demote_top_title: bool = False,
):
    source_dir = source_dir.resolve()
    output_dir = output_dir.resolve()
    output_dir.mkdir(parents=True, exist_ok=True)

    lines = []
    for frag in fragments:
        rst_file = Path(frag)
        if not rst_file.is_file():
            print(f"error: missing fragment: {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)

        if demote_top_title:
            body = _demote_top_title(rst_file.read_text(encoding="utf-8"))
            lines.append(body.rstrip() + "\n")
        else:
            lines.append(f".. include:: /{rel.as_posix()}")
            lines.append("")

    out_path = output_dir / f"{out_basename}.rst.inc"
    out_path.write_text("\n".join(lines) + ("\n" if lines else ""), encoding="utf-8")
    print(f"Wrote {out_path} ({len(fragments)} fragments)")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Write OUT_BASENAME.rst.inc with ordered includes or inlined bodies."
    )
    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 file.",
    )
    parser.add_argument(
        "out_basename",
        help="Basename for the include file (e.g. misc_body → misc_body.rst.inc).",
    )
    parser.add_argument(
        "fragments",
        nargs="+",
        help="Fragment .rst paths in canonical Makefile order.",
    )
    parser.add_argument(
        "--demote-top-title",
        action="store_true",
        help="Inline fragments and demote each file's first ==== title to ----.",
    )
    args = parser.parse_args()
    write_bundle(
        Path(args.source_dir),
        Path(args.output_dir),
        args.out_basename,
        args.fragments,
        demote_top_title=args.demote_top_title,
    )
