"""Tests for complyform.core.remediator.dependency_resolver."""

from __future__ import annotations

from complyform.core.assessor.control_matcher import Finding
from complyform.core.remediator.dependency_resolver import (
    DependencyReport,
    DependencyResolver,
    build_dependency_report,
)
from complyform.core.remediator.patch_generator import PatchFile


def _patch(
    control_id: str = "CC6.1",
    dependencies: list[str] | None = None,
    risk_level: str = "low",
) -> PatchFile:
    return PatchFile(
        resource_address="google_sql_database_instance.main",
        control_id=control_id,
        requirement_id=None,
        resource_type="google_sql_database_instance",
        filename=f"patch_{control_id}.tf",
        content="# patch",
        diff="",
        strategy="state_only",
        dependencies=dependencies or [],
        risk_level=risk_level,
    )


def _finding(control_id: str = "CC6.1") -> Finding:
    return Finding(
        control_id=control_id,
        framework="soc2",
        resource_address="google_sql_database_instance.main",
        resource_type="google_sql_database_instance",
        status="FAIL",
        severity="HIGH",
        finding=f"Control {control_id} failed",
        remediation="Fix it",
        checkov_id="CKV_GCP_6",
        cross_mappings=None,
        native_ids=None,
        confidence="high",
    )


class TestDependencyResolver:
    def test_no_deps_passthrough(self) -> None:
        patches = [_patch(), _patch(control_id="CC6.7")]
        resolver = DependencyResolver()
        result = resolver.resolve(patches)
        assert len(result) == 2

    def test_deps_after_no_deps(self) -> None:
        p_no_dep = _patch(control_id="CC6.1")
        p_with_dep = _patch(
            control_id="CC6.7",
            dependencies=["google_kms_key_ring.main"],
        )
        resolver = DependencyResolver()
        result = resolver.resolve([p_with_dep, p_no_dep])
        assert result[0].control_id == "CC6.1"
        assert result[1].control_id == "CC6.7"

    def test_linear_chain_correct_order(self) -> None:
        p1 = _patch(control_id="A")
        p2 = _patch(
            control_id="B",
            dependencies=["google_kms_key_ring.x"],
        )
        resolver = DependencyResolver()
        result = resolver.resolve([p2, p1])
        assert result[0].control_id == "A"
        assert result[1].control_id == "B"


class TestBuildDependencyReport:
    def test_no_deps_returns_none(self) -> None:
        patches = [_patch()]
        report = build_dependency_report(patches, [_finding()])
        assert report is None

    def test_with_deps_returns_report(self) -> None:
        patches = [
            _patch(
                dependencies=["google_kms_key_ring.main_ring"],
                risk_level="medium",
            )
        ]
        report = build_dependency_report(patches, [_finding()])
        assert report is not None
        assert isinstance(report, DependencyReport)
        assert len(report.new_resources) == 1
        dep = report.new_resources[0]
        assert dep.resource_type == "google_kms_key_ring"
        assert dep.resource_name == "main_ring"
        assert dep.risk_level == "medium"

    def test_high_risk_flagged(self) -> None:
        patches = [
            _patch(
                dependencies=["google_iam_policy.admin"],
                risk_level="high",
            )
        ]
        report = build_dependency_report(patches, [_finding()])
        assert report is not None
        assert report.new_resources[0].risk_level == "high"
        assert "HIGH RISK" in report.new_resources[0].review_hint

    def test_diamond_dedup(self) -> None:
        p1 = _patch(
            control_id="CC6.1",
            dependencies=["google_kms_key_ring.shared"],
        )
        p2 = _patch(
            control_id="CC6.7",
            dependencies=["google_kms_key_ring.shared"],
        )
        report = build_dependency_report(
            [p1, p2], [_finding(), _finding(control_id="CC6.7")]
        )
        assert report is not None
        assert len(report.new_resources) == 1
        assert set(report.new_resources[0].required_by_controls) == {"CC6.1", "CC6.7"}
