#!/usr/bin/env python3
"""PKG-12 gate: no residual pypi.org publish/distribution surface for ``mgf-*``.

After the Codeberg cutover (``docs/standards/PACKAGE_DISTRIBUTION.md``,
PKG-01..12), no ``mgf-*`` publish command, token, index, or verify step may
target pypi.org. This gate fails CI if ``pypi.org`` appears in the *functional*
publish/resolution surface — ``.woodpecker*.yml`` + ``pyproject.toml`` — outside
an explicit allowlist:

  - comment lines (explanatory / historical context),
  - negations (``not pypi.org``, ``never pypi.org``, ...),
  - third-party ``--extra-index-url`` fallbacks (PKG-06 keeps *public* PyPI for
    non-``mgf-*`` dependencies; only ``mgf-*`` are pinned to Codeberg).

Docs / CHANGELOG / source are intentionally NOT scanned — a historical pypi.org
link there is fine; only the config that actually drives publish + resolution
matters. Like ``scripts/check_sbom.py`` / ``scripts/verify_codeberg.py`` this is
a single self-contained stdlib script so it runs identically on the server and
under ``woodpecker-cli exec`` (``scripts/ci-local.sh``).
"""

from __future__ import annotations

import re
import sys
from pathlib import Path

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

# The functional publish + dependency-resolution surface PKG-12 governs
# ("publish command, token, index, or verify step"). Source / docs / CHANGELOG
# are deliberately excluded.
_SCAN_NAMES = (".woodpecker.yml", "pyproject.toml")

# "not pypi.org", "never pypi.org", "no longer ... pypi.org", "≠ pypi.org", etc.
_NEGATION = re.compile(r"(?:not|never|no longer|off|away from|≠|!=)\b[^\n]{0,24}pypi\.org", re.I)


def _allowed(line: str) -> bool:
    """True if a ``pypi.org`` mention on this line is permitted by PKG-12."""
    return (
        line.lstrip().startswith("#")  # explanatory / historical comment
        or _NEGATION.search(line) is not None  # an explicit "NOT pypi.org" line
        or "extra-index-url" in line  # third-party fallback — PyPI for non-mgf-* (PKG-06)
    )


def _targets() -> list[Path]:
    targets = [ROOT / name for name in _SCAN_NAMES if (ROOT / name).exists()]
    wp_dir = ROOT / ".woodpecker"
    if wp_dir.is_dir():
        targets.extend(sorted(wp_dir.glob("*.yml")))
    return targets


def main() -> int:
    violations: list[str] = []
    targets = _targets()
    for path in targets:
        for lineno, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
            if "pypi.org" in line and not _allowed(line):
                violations.append(f"{path.relative_to(ROOT)}:{lineno}: {line.strip()}")

    if violations:
        sys.stderr.write(
            "PKG-12 no-pypi-publish-surface gate FAILED — mgf-* must not target "
            "pypi.org for publish / token / index / verify (PACKAGE_DISTRIBUTION.md "
            "PKG-12). Allowlist: comments, 'not pypi.org' negations, and "
            "--extra-index-url third-party fallbacks. Offending lines:\n"
        )
        for v in violations:
            sys.stderr.write(f"  {v}\n")
        return 1

    print(f"PKG-12 gate OK — no residual pypi.org publish surface in {len(targets)} scanned file(s).")
    return 0


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