"""Tests for OPA/Rego generator."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from complyform.core.generators.opa_rego import OpaRegoGenerator, RegoFile, RegoRule

if TYPE_CHECKING:
    from pathlib import Path


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


@pytest.fixture
def sample_findings() -> list[dict[str, object]]:
    return [
        {
            "control_id": "CC6.1",
            "framework": "soc2",
            "resource_address": "google_sql_database_instance.main",
            "resource_type": "google_sql_database_instance",
            "status": "FAIL",
            "severity": "CRITICAL",
            "finding": "Database encryption not enabled",
            "remediation": "Enable encryption",
            "checkov_id": "CKV_GCP_6",
            "native_ids": {"scc": "SQL_CMEK_DISABLED"},
            "cross_mappings": [{"framework": "hipaa", "control_id": "164.312"}],
            "confidence": "verified",
        },
    ]


class TestOpaRegoGenerator:
    def test_format_id(self, generator: OpaRegoGenerator) -> None:
        assert generator.FORMAT_ID == "opa"

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

    def test_format_name(self, generator: OpaRegoGenerator) -> None:
        assert generator.format_name() == "OPA/Rego"

    @pytest.mark.parametrize("cloud", ["gcp", "aws", "azure"])
    def test_generates_rego_per_cloud(
        self,
        generator: OpaRegoGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
        cloud: str,
    ) -> None:
        # Adjust resource_type per cloud
        for f in sample_findings:
            if cloud == "aws":
                f["resource_type"] = "aws_rds_instance"
            elif cloud == "azure":
                f["resource_type"] = "azurerm_mssql_server"

        result = generator.generate(sample_findings, {}, cloud, "team", tmp_path)
        assert result.artifact_count > 0
        for f in result.files_written:
            assert f.exists()
            content = f.read_text()
            assert f"package complyform.{cloud}." in content

    def test_rego_contains_import_rego_v1(
        self,
        generator: OpaRegoGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        result = generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        for f in result.files_written:
            content = f.read_text()
            assert "import rego.v1" in content

    def test_rego_contains_deny_rule(
        self,
        generator: OpaRegoGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        result = generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        for f in result.files_written:
            content = f.read_text()
            assert "deny contains msg if" in content

    def test_output_dir_structure(
        self,
        generator: OpaRegoGenerator,
        sample_findings: list[dict[str, object]],
        tmp_path: Path,
    ) -> None:
        result = generator.generate(sample_findings, {}, "gcp", "team", tmp_path)
        for f in result.files_written:
            # Should be under {output}/opa/{cloud}/
            assert "opa" in str(f)
            assert "gcp" in str(f)
            assert f.suffix == ".rego"

    def test_empty_findings(self, generator: OpaRegoGenerator, tmp_path: Path) -> None:
        result = generator.generate([], {}, "gcp", "team", tmp_path)
        assert result.artifact_count == 0
        assert result.files_written == []

    def test_multiple_controls_same_resource(
        self, generator: OpaRegoGenerator, tmp_path: Path
    ) -> None:
        findings = [
            {
                "control_id": "CC6.1",
                "framework": "soc2",
                "resource_type": "google_sql_database_instance",
                "resource_address": "google_sql_database_instance.a",
                "status": "FAIL",
                "severity": "CRITICAL",
                "finding": "Encryption missing",
                "remediation": "",
                "checkov_id": None,
                "native_ids": None,
                "cross_mappings": None,
                "confidence": "high",
            },
            {
                "control_id": "CC7.2",
                "framework": "soc2",
                "resource_type": "google_sql_database_instance",
                "resource_address": "google_sql_database_instance.b",
                "status": "FAIL",
                "severity": "HIGH",
                "finding": "Backup missing",
                "remediation": "",
                "checkov_id": None,
                "native_ids": None,
                "cross_mappings": None,
                "confidence": "high",
            },
        ]
        result = generator.generate(findings, {}, "gcp", "team", tmp_path)
        # Single file for same resource type
        assert result.artifact_count == 1
        content = result.files_written[0].read_text()
        # Multiple deny rules
        assert content.count("deny contains msg if") == 2

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


class TestRegoModels:
    def test_rego_rule(self) -> None:
        rule = RegoRule(
            control_id="CC6.1",
            framework="soc2",
            checkov_id="CKV_GCP_6",
            native_ids=None,
            severity="CRITICAL",
            description="test",
            resource_type="google_sql_database_instance",
            check_field="encryption",
        )
        assert rule.control_id == "CC6.1"

    def test_rego_file(self) -> None:
        rf = RegoFile(cloud="gcp", resource_type="google_sql_database_instance")
        assert rf.rules == []
