"""``mgf-fed local-ci`` — run the real ``.woodpecker`` pipeline locally.

A thin wrapper over ``woodpecker-cli exec`` (the official local pipeline runner): it executes
a repo's actual ``.woodpecker.yml`` in containers, so it covers the *full* gate set (incl.
mypy / pytest matrix / vuln-scan / sbom) with each step installing its own deps — the
dependency-heavy complement to the fast static ``mgf-fed gates``.

Caveats (inherent to local exec): needs Docker running; tag-gated publish steps are skipped
without a tag; pulling *private* mgf-* deps inside a step may need a token in the environment.
"""

from __future__ import annotations

import os
import shutil
import subprocess
from pathlib import Path

from mgf.fed._logging import LOG, log_operation
from mgf.fed._roster import federation_root, members


def _woodpecker_cli() -> str | None:
    return shutil.which("woodpecker-cli") or shutil.which("woodpecker")


def run_local_ci(repos: list[str], *, root: Path | None = None) -> int:
    with log_operation("local_ci.exec", repos=len(repos)):
        return _run_local_ci(repos, root=root)


def _run_local_ci(repos: list[str], *, root: Path | None = None) -> int:
    wp = _woodpecker_cli()
    if wp is None:
        print("woodpecker-cli not found on PATH — install it (https://woodpecker-ci.org/docs/cli).")
        return 2
    if shutil.which("docker") is None:
        print("docker not found on PATH — local-ci runs the pipeline in containers.")
        return 2

    root = root or federation_root()
    by_repo = {m.repo: m for m in members(root)}
    rc_all = 0
    for r in repos:
        m = by_repo.get(r)
        repo_dir = m.repo_dir if m is not None else root / r
        wp_file = repo_dir / ".woodpecker.yml"
        if not wp_file.is_file():
            print(f"  {r}: no .woodpecker.yml — skip")
            continue
        print(f"  {r}: woodpecker-cli exec …")
        try:
            p = subprocess.run(  # noqa: S603
                [wp, "exec"],
                cwd=str(repo_dir),
                capture_output=True,
                text=True,
                timeout=int(os.environ.get("MGF_FED_LOCALCI_TIMEOUT_S", "1800")),  # SC-07
            )
        except (OSError, subprocess.TimeoutExpired) as exc:
            # LG-05: ship the traceback centrally rather than only printing repr.
            LOG.error("woodpecker-cli exec failed for %s", r, exc_info=True)
            print(f"  {r}: ERROR running woodpecker-cli — {exc}")
            rc_all = 1
            continue
        if p.returncode == 0:
            print(f"  {r}: PASS")
        else:
            rc_all = 1
            tail = "\n      ".join((p.stdout + p.stderr).strip().splitlines()[-6:])
            print(f"  {r}: FAIL (rc={p.returncode})\n      {tail}")
    return rc_all
