"""Tests for complyform.core.assessor.overlap_hints.compute_overlap_hints."""

from __future__ import annotations

from complyform.core.assessor.control_matcher import Finding
from complyform.core.assessor.overlap_hints import compute_overlap_hints
from complyform.core.profiles.models import ControlCrossMapping, CrossMappingIndex


def _make_finding(
    control_id: str,
    framework: str,
    status: str = "PASS",
    severity: str = "MEDIUM",
) -> Finding:
    return Finding(
        control_id=control_id,
        framework=framework,
        resource_address="module.test.resource_addr",
        resource_type="google_compute_instance",
        status=status,
        severity=severity,
        finding=f"Control {control_id} {status.lower()}",
        remediation="",
        checkov_id=None,
        cross_mappings=None,
        native_ids=None,
        confidence="high",
    )


def _make_cross_mapping(
    src_fw: str,
    src_ctrl: str,
    tgt_fw: str,
    tgt_ctrl: str,
) -> ControlCrossMapping:
    return ControlCrossMapping(
        source_framework=src_fw,
        source_control=src_ctrl,
        target_framework=tgt_fw,
        target_control=tgt_ctrl,
        relationship="equivalent",
    )


class TestNoOverlap:
    def test_no_cross_mappings_returns_none(self) -> None:
        findings = [_make_finding("CC6.1", "soc2")]
        index = CrossMappingIndex(schema_version=1, mappings=[])
        result = compute_overlap_hints(
            findings, index, frozenset({"soc2"}), frozenset({"soc2", "iso27001"})
        )
        assert result is None

    def test_no_findings_returns_none(self) -> None:
        index = CrossMappingIndex(
            schema_version=1,
            mappings=[_make_cross_mapping("soc2", "CC6.1", "iso27001", "A.8.3")],
        )
        result = compute_overlap_hints(
            [], index, frozenset({"soc2"}), frozenset({"soc2", "iso27001"})
        )
        assert result is None


class TestOverlapBelowThreshold:
    def test_overlap_at_or_below_30_returns_none(self) -> None:
        """When overlap_pct <= 30%, the framework should not appear."""
        # 10 findings for soc2, but only 1 cross-mapped to iso27001 → 10%
        findings = [_make_finding(f"CC{i}.1", "soc2") for i in range(10)]
        index = CrossMappingIndex(
            schema_version=1,
            mappings=[_make_cross_mapping("soc2", "CC0.1", "iso27001", "A.8.3")],
        )
        result = compute_overlap_hints(
            findings, index, frozenset({"soc2"}), frozenset({"soc2", "iso27001"})
        )
        assert result is None


class TestValidOverlap:
    def test_returns_correct_structure_sorted_desc(self) -> None:
        """Overlap > 30% produces results sorted by overlap_pct descending."""
        # 2 findings, both cross-map → 100% overlap for each target framework
        findings = [
            _make_finding("CC6.1", "soc2"),
            _make_finding("CC6.2", "soc2", status="FAIL"),
        ]
        mappings = [
            _make_cross_mapping("soc2", "CC6.1", "iso27001", "A.8.3"),
            _make_cross_mapping("soc2", "CC6.2", "iso27001", "A.8.4"),
            _make_cross_mapping("soc2", "CC6.1", "pci_dss", "1.1"),
        ]
        index = CrossMappingIndex(schema_version=1, mappings=mappings)
        result = compute_overlap_hints(
            findings,
            index,
            frozenset({"soc2"}),
            frozenset({"soc2", "iso27001", "pci_dss"}),
        )
        assert result is not None
        assert len(result) == 2

        # Both should have required keys
        for hint in result:
            assert "framework" in hint
            assert "shared_controls" in hint
            assert "passing_shared" in hint
            assert "overlap_pct" in hint

        # Sorted descending by overlap_pct
        pcts = [h["overlap_pct"] for h in result]
        assert pcts == sorted(pcts, reverse=True)

    def test_passing_shared_counted_correctly(self) -> None:
        """passing_shared only counts controls that actually PASS."""
        findings = [
            _make_finding("CC6.1", "soc2", status="PASS"),
            _make_finding("CC6.2", "soc2", status="FAIL"),
        ]
        mappings = [
            _make_cross_mapping("soc2", "CC6.1", "iso27001", "A.8.3"),
            _make_cross_mapping("soc2", "CC6.2", "iso27001", "A.8.4"),
        ]
        index = CrossMappingIndex(schema_version=1, mappings=mappings)
        result = compute_overlap_hints(
            findings,
            index,
            frozenset({"soc2"}),
            frozenset({"soc2", "iso27001"}),
        )
        assert result is not None
        iso_hint = result[0]
        assert iso_hint["framework"] == "iso27001"
        assert iso_hint["shared_controls"] == 2
        assert iso_hint["passing_shared"] == 1


class TestMaxFiveResults:
    def test_max_5_results_enforced(self) -> None:
        """Even with many eligible frameworks, only top 5 are returned."""
        findings = [_make_finding("CC6.1", "soc2")]
        target_fws = [f"fw_{i}" for i in range(8)]
        mappings = [
            _make_cross_mapping("soc2", "CC6.1", fw, "ctrl.1") for fw in target_fws
        ]
        index = CrossMappingIndex(schema_version=1, mappings=mappings)
        all_fws = frozenset({"soc2"} | set(target_fws))
        result = compute_overlap_hints(findings, index, frozenset({"soc2"}), all_fws)
        assert result is not None
        assert len(result) <= 5


class TestUserFrameworkExcluded:
    def test_user_already_has_framework_excluded(self) -> None:
        """Frameworks the user already selected should not appear in hints."""
        findings = [_make_finding("CC6.1", "soc2")]
        mappings = [
            _make_cross_mapping("soc2", "CC6.1", "iso27001", "A.8.3"),
        ]
        index = CrossMappingIndex(schema_version=1, mappings=mappings)
        # iso27001 is in user_remediate_frameworks → excluded
        result = compute_overlap_hints(
            findings,
            index,
            frozenset({"soc2", "iso27001"}),
            frozenset({"soc2", "iso27001"}),
        )
        assert result is None
