"""Generated CI guard-lines (SPEC-P4 §2 / PROPOSAL §2.6, the in-pipe net).

Every generated step that consumes a ``from_secret`` as a shell ENV VAR and REQUIRES
it carries a fail-fast guard in the ``$DEVPI_URL`` shape, so an empty injection (the
CIR-02 silent-empty class) turns LOUD at the first affected step instead of running
zero steps in error-status. "Guard the guard": a step that legitimately tolerates the
secret's absence carries NONE (no false-red), and a clone plugin's ``settings``
from_secret (not a shell env var) carries none either — there is no shell to guard.

These are static template-content pins; the fleet re-render is verified separately by
the drift-check going clean (Fable's court step, not run here).
"""

from __future__ import annotations

from pathlib import Path

import pytest

_TEMPLATES = Path(__file__).resolve().parents[2] / "templates" / "woodpecker"


def _read(name: str) -> str:
    return (_TEMPLATES / name).read_text(encoding="utf-8")


def _step_block(text: str, step_name: str) -> str:
    """The lines of the ``- name: <step_name>`` step, up to the next 2-space step."""
    lines = text.splitlines()
    start = next((i for i, ln in enumerate(lines) if ln.strip() == f"- name: {step_name}"), None)
    assert start is not None, f"step {step_name!r} not found"
    indent = len(lines[start]) - len(lines[start].lstrip())
    out = [lines[start]]
    for ln in lines[start + 1 :]:
        if ln.strip().startswith("- name:") and (len(ln) - len(ln.lstrip())) == indent:
            break
        out.append(ln)
    return "\n".join(out)


def _guard_for(env_var: str, secret: str) -> str:
    """The exact fail-fast guard line the template must carry for ``env_var``."""
    return (
        f'[ -n "${env_var}" ] || {{ echo "FATAL: {secret} injected empty '
        '-- check its Woodpecker scope for this event (mgf-secrets doctor)"; exit 1; }'
    )


# --------------------------------------------------------------------------- #
# Required env-var from_secret steps carry a correctly-scoped guard.
# --------------------------------------------------------------------------- #


def test_publish_step_guards_devpi_password() -> None:
    block = _step_block(_read("base.yml"), "publish")
    # The step consumes devpi_password as $TWINE_PASSWORD and REQUIRES it (tag-only).
    assert "from_secret: devpi_password" in block
    assert _guard_for("TWINE_PASSWORD", "devpi_password") in block
    # The guard precedes the consuming command (twine upload).
    assert block.index("TWINE_PASSWORD") < block.index("twine upload")


def test_ping_siblings_step_guards_woodpecker_token() -> None:
    block = _step_block(_read("frag-cornerstone-ping.yml"), "ping-siblings")
    assert "from_secret: woodpecker_token" in block
    assert _guard_for("WOODPECKER_TOKEN", "woodpecker_token") in block
    assert block.index("WOODPECKER_TOKEN") < block.index("mgf-fed ping-siblings")


def test_guards_match_the_devpi_url_fail_fast_shape() -> None:
    """One greppable guard shape across the fleet: `[ -n "$X" ] || { echo …; exit 1; }`."""
    base = _read("base.yml")
    assert '[ -n "$DEVPI_URL" ]' in base  # the reference shape
    for env_var in ("TWINE_PASSWORD",):
        assert f'[ -n "${env_var}" ] || {{ echo "FATAL:' in base
        assert "exit 1; }" in base


# --------------------------------------------------------------------------- #
# "Guard the guard": tolerated / non-shell secrets carry NO fatal guard.
# --------------------------------------------------------------------------- #


def test_zig_clone_token_is_not_fatally_guarded() -> None:
    """A leaf Zig repo legitimately tolerates an empty codeberg_clone_token (netrc
    no-op) — a fatal guard would false-red it, so there must be none."""
    block = _step_block(_read("base-zig.yml"), "zig-build-and-test")
    assert "from_secret: codeberg_clone_token" in block
    # No FATAL fail-fast command for this secret (a comment MENTIONING the pattern is
    # fine — we check for the actual guard: the `|| { echo "FATAL: …` command form).
    assert '[ -n "$CODEBERG_CLONE_TOKEN" ] || {' not in block
    assert "FATAL: codeberg_clone_token" not in block
    # …and the reason is documented so the WF-13 re-render never "fixes" it.
    assert "guard the guard" in block.lower()


@pytest.mark.parametrize("template", ["base.yml", "base-zig.yml"])
def test_clone_plugin_ssh_secrets_carry_no_shell_guard(template: str) -> None:
    """The clone step feeds its ssh secrets through plugin ``settings:`` (no shell
    ``commands:``), so a `[ -n … ]` guard is neither possible nor present — plugin-git
    fails loud on a bad key on its own; this is not the silent-empty class."""
    block = _step_block(_read(template), "clone")
    assert "from_secret: codeberg_ssh_clone_key" in block
    assert '[ -n "$' not in block  # no shell guard in a plugin-settings step
