"""AC-4: GitHub Actions workflows under `.github/workflows/` are valid.

YAML syntactic validity + ADR-002 dual-binary build matrix check always run.
`actionlint` semantic validation runs only when the binary is on PATH; CI
installs it as a job step.
"""

from __future__ import annotations

import shutil
import subprocess
from pathlib import Path

import pytest
import yaml

REPO_ROOT = Path(__file__).resolve().parents[2]
WORKFLOWS_DIR = REPO_ROOT / ".github" / "workflows"
WORKFLOWS = sorted(WORKFLOWS_DIR.glob("*.yml"))


def test_workflows_dir_populated() -> None:
    # Assert
    names = {p.name for p in WORKFLOWS}
    assert {"ci.yml", "ci-tier2.yml", "release.yml", "cve-rescan.yml"} <= names


@pytest.mark.parametrize("workflow", WORKFLOWS, ids=[p.name for p in WORKFLOWS])
def test_workflow_yaml_parses(workflow: Path) -> None:
    # Act
    data = yaml.safe_load(workflow.read_text())
    # Assert
    assert isinstance(data, dict), f"{workflow.name} must parse to a mapping"
    # GitHub Actions reserves `on` as a top-level key; PyYAML preserves it as a
    # bool-style key, so also accept the bool key `True` produced by safe_load.
    assert "on" in data or True in data, f"{workflow.name} missing trigger block"
    assert data.get("jobs"), f"{workflow.name} must declare jobs"


def test_ci_yml_has_dual_binary_matrix() -> None:
    """ADR-002: deployment + research must both build in ci.yml."""
    # Arrange
    raw = (WORKFLOWS_DIR / "ci.yml").read_text()
    # Assert
    # Match the matrix dimension we care about without depending on YAML key order.
    assert "deployment" in raw, "ci.yml matrix must include `deployment` kind"
    assert "research" in raw, "ci.yml matrix must include `research` kind"
    assert "matrix:" in raw, "ci.yml build job must use a strategy matrix"


def test_actionlint_passes() -> None:
    # Arrange
    actionlint = shutil.which("actionlint")
    if actionlint is None:
        pytest.skip("actionlint not on PATH; CI installs it before the lint job")

    # Act
    result = subprocess.run(
        [actionlint, *(str(p) for p in WORKFLOWS)],
        capture_output=True,
        text=True,
        check=False,
    )

    # Assert
    assert result.returncode == 0, (
        f"actionlint reported errors:\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}"
    )
