"""Tests for GitHub Actions linter."""

from yaml_doctor.analyzers.github_actions import lint_github_actions


class TestGitHubActionsLinter:
    def _workflow(self, **overrides):
        doc = {
            "name": "CI",
            "on": {"push": {"branches": ["main"]}},
            "permissions": {"contents": "read"},
            "jobs": {
                "build": {
                    "name": "Build",
                    "runs-on": "ubuntu-22.04",
                    "timeout-minutes": 30,
                    "steps": [
                        {"uses": "actions/checkout@v4", "with": {"persist-credentials": False}},
                        {"name": "Test", "run": "npm test"},
                    ],
                }
            },
            "concurrency": {"group": "ci-${{ github.ref }}", "cancel-in-progress": True},
        }
        for k, v in overrides.items():
            if k == "permissions":
                doc["permissions"] = v
            elif k == "no_name":
                del doc["jobs"]["build"]["name"]
            elif k == "no_timeout":
                del doc["jobs"]["build"]["timeout-minutes"]
            elif k == "no_concurrency":
                del doc["concurrency"]
            elif k == "latest_runner":
                doc["jobs"]["build"]["runs-on"] = "ubuntu-latest"
            elif k == "steps":
                doc["jobs"]["build"]["steps"] = v
            elif k == "trigger":
                doc["on"] = v
        return doc

    def test_clean(self):
        doc = self._workflow()
        findings = lint_github_actions([doc])
        # Clean workflow should have no critical/high
        high_crit = [f for f in findings if f.rule.severity.value in ("critical", "high")]
        assert len(high_crit) == 0

    def test_gha001_mutable_ref(self):
        doc = self._workflow(steps=[
            {"uses": "actions/checkout@main"},
        ])
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA001" for f in findings)

    def test_gha001_sha_ok(self):
        doc = self._workflow(steps=[
            {"uses": "actions/checkout@abcdef1234567890abcdef1234567890abcdef12"},
        ])
        findings = lint_github_actions([doc])
        assert not any(f.rule.rule_id == "GHA001" for f in findings)

    def test_gha002_persist_creds(self):
        doc = self._workflow(steps=[
            {"uses": "actions/checkout@v4", "with": {"persist-credentials": True}},
        ])
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA002" for f in findings)

    def test_gha003_secrets_in_run(self):
        doc = self._workflow(steps=[
            {"name": "Deploy", "run": "echo ${{ secrets.TOKEN }}"},
        ])
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA003" for f in findings)

    def test_gha004_broad_perms(self):
        doc = self._workflow(permissions="write-all")
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA004" for f in findings)

    def test_gha005_no_timeout(self):
        doc = self._workflow(no_timeout=True)
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA005" for f in findings)

    def test_gha006_pr_target(self):
        doc = self._workflow(trigger={"pull_request_target": {"branches": ["main"]}})
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA006" for f in findings)

    def test_gha007_no_concurrency(self):
        doc = self._workflow(no_concurrency=True)
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA007" for f in findings)

    def test_gha008_latest_runner(self):
        doc = self._workflow(latest_runner=True)
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA008" for f in findings)

    def test_gha009_script_injection(self):
        doc = self._workflow(steps=[
            {"name": "Greet", "run": "echo ${{ github.event.issue.title }}"},
        ])
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA009" for f in findings)

    def test_gha010_missing_name(self):
        doc = self._workflow()
        del doc["name"]  # Remove workflow-level name
        findings = lint_github_actions([doc])
        assert any(f.rule.rule_id == "GHA010" for f in findings)

    def test_empty_docs(self):
        assert lint_github_actions([]) == []
