#!/usr/bin/env python3
"""Generate the CycloneDX SBOM for the installed environment and validate it.

This is the CI ``sbom`` step's logic, extracted from an inline
``.woodpecker.yml`` heredoc. Inline multi-line shell — command substitution,
backslash line-continuations, and ``python - <<'PYEOF'`` heredocs — does not
survive ``woodpecker-cli exec`` (``scripts/ci-local.sh``) faithfully, so the
step would pass on the server but fail locally. A single self-contained script
runs identically in both places.

Writes ``dist/mgf-common-<version>.cdx.json`` and asserts it is well-formed
CycloneDX naming mgf-common as the main component with a non-empty closure.
"""

from __future__ import annotations

import json
import re
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]


def _fail(msg: str) -> None:
    sys.stderr.write(f"sbom: {msg}\n")
    raise SystemExit(1)


def _project_version() -> str:
    text = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
    match = re.search(r'^version = "([^"]+)"', text, re.MULTILINE)
    if not match:
        _fail("could not read version from pyproject.toml")
    return match.group(1)  # type: ignore[union-attr]


def main() -> int:
    version = _project_version()
    dist = ROOT / "dist"
    dist.mkdir(exist_ok=True)
    sbom_path = dist / f"mgf-common-{version}.cdx.json"

    subprocess.run(  # noqa: S603 — fixed argv, no shell
        [
            "cyclonedx-py",
            "environment",
            "--pyproject",
            str(ROOT / "pyproject.toml"),
            "--mc-type",
            "library",
            "--of",
            "JSON",
            "--output-reproducible",
            "-o",
            str(sbom_path),
            sys.executable,
        ],
        check=True,
    )

    doc = json.loads(sbom_path.read_text(encoding="utf-8"))
    if doc.get("bomFormat") != "CycloneDX":
        _fail(f"bomFormat={doc.get('bomFormat')!r}")
    if not str(doc.get("specVersion", "")).startswith("1."):
        _fail(f"specVersion={doc.get('specVersion')!r}")
    component = doc.get("metadata", {}).get("component", {})
    if component.get("name") != "mgf-common":
        _fail(f"main.name={component.get('name')!r}")
    if component.get("version") != version:
        _fail(f"main.version={component.get('version')!r} (expected {version})")
    n_components = len(doc.get("components", []))
    if n_components == 0:
        _fail("SBOM lists zero components")

    print(
        f"OK: SBOM at {sbom_path} — "
        f"main=mgf-common@{version} components={n_components}"
    )
    return 0


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