"""Tests for GitHub Action generator."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from complyform.core.errors import ComplyFormError
from complyform.core.generators.github_action import (
    GitHubActionGenerator,
    _validate_pins,
)

if TYPE_CHECKING:
    from pathlib import Path


@pytest.fixture
def generator() -> GitHubActionGenerator:
    return GitHubActionGenerator()


@pytest.fixture
def sample_findings() -> list[dict[str, object]]:
    return [
        {
            "control_id": "CC6.1",
            "framework": "soc2",
            "resource_type": "google_sql_database_instance",
            "resource_address": "google_sql_database_instance.main",
            "status": "FAIL",
            "severity": "CRITICAL",
            "finding": "Test",
            "remediation": "Fix",
            "checkov_id": None,
            "native_ids": None,
            "cross_mappings": None,
            "confidence": "high",
        }
    ]


class TestGitHubActionGenerator:
    def test_format_id(self, generator: GitHubActionGenerator) -> None:
        assert generator.FORMAT_ID == "github-action"

    def test_tier_feature(self, generator: GitHubActionGenerator) -> None:
        assert generator.TIER_FEATURE == "github_action"

    def test_format_name(self, generator: GitHubActionGenerator) -> None:
        assert generator.format_name() == "GitHub Action"

    def test_pro_tier_no_opa_step(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "pro", tmp_path)
        workflow = tmp_path / ".github" / "workflows" / "complyform-compliance.yaml"
        content = workflow.read_text()
        assert "OPA/Conftest" not in content
        assert "Push to Dashboard" not in content

    def test_team_tier_has_opa_step(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        workflow = tmp_path / ".github" / "workflows" / "complyform-compliance.yaml"
        content = workflow.read_text()
        assert "OPA/Conftest" in content
        assert "Push to Dashboard" in content

    def test_agency_tier_same_as_team(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "agency", tmp_path)
        workflow = tmp_path / ".github" / "workflows" / "complyform-compliance.yaml"
        content = workflow.read_text()
        assert "OPA/Conftest" in content

    def test_sha_pins_not_tags(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        workflow = tmp_path / ".github" / "workflows" / "complyform-compliance.yaml"
        content = workflow.read_text()
        # All uses: should have @ followed by hex SHA
        import re

        uses_lines = [
            line_text for line_text in content.split("\n") if "uses:" in line_text
        ]
        for line in uses_lines:
            assert "@" in line
            # After @, should be hex chars
            sha_part = line.split("@")[-1].strip()
            assert re.match(r"^[a-f0-9]+$", sha_part), f"Non-SHA pin: {line}"

    def test_reject_sha_placeholder(self) -> None:
        with pytest.raises(ComplyFormError, match="placeholder SHA"):
            _validate_pins({"actions/checkout": "<sha>"})

    def test_workflow_triggers(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        workflow = tmp_path / ".github" / "workflows" / "complyform-compliance.yaml"
        content = workflow.read_text()
        assert "pull_request:" in content
        assert "push:" in content
        assert "schedule:" in content
        assert "workflow_dispatch:" in content

    def test_minimal_permissions(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        workflow = tmp_path / ".github" / "workflows" / "complyform-compliance.yaml"
        content = workflow.read_text()
        assert "contents: read" in content
        assert "pull-requests: write" in content
        assert "id-token: write" in content

    @pytest.mark.parametrize(
        ("tier", "expected"),
        [
            ("community", False),
            ("pro", True),
            ("team", True),
            ("agency", True),
        ],
    )
    def test_supports_tier(
        self, generator: GitHubActionGenerator, tier: str, expected: bool
    ) -> None:
        assert generator.supports_tier(tier) is expected

    def test_generates_readme(
        self,
        generator: GitHubActionGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        readme = tmp_path / "README-complyform-ci.md"
        assert readme.exists()
