"""Tests for complyform.core.profiles.validators — all paths."""

from __future__ import annotations

from typing import TYPE_CHECKING
from unittest.mock import patch

if TYPE_CHECKING:
    from pathlib import Path

from complyform.core.profiles.control_loader import _reset_cache as reset_ctrl
from complyform.core.profiles.mapping_loader import _reset_cache as reset_map
from complyform.core.profiles.registry import _reset_cache as reset_reg
from complyform.core.profiles.validators import validate_framework_profile


def _reset_all() -> None:
    reset_ctrl()
    reset_map()
    reset_reg()


class TestValidateHappyPath:
    def test_soc2_gcp(self) -> None:
        warnings = validate_framework_profile("soc2", "gcp")
        assert warnings == []

    def test_soc2_aws(self) -> None:
        warnings = validate_framework_profile("soc2", "aws")
        assert warnings == []

    def test_soc2_azure(self) -> None:
        warnings = validate_framework_profile("soc2", "azure")
        assert warnings == []

    def test_cis_gcp(self) -> None:
        warnings = validate_framework_profile("cis_gcp", "gcp")
        assert warnings == []


class TestValidateRegistryFailure:
    def test_nonexistent_framework(self) -> None:
        warnings = validate_framework_profile("nonexistent_xyz", "gcp")
        assert len(warnings) == 1
        assert "Registry" in warnings[0]


class TestValidateControlsFailure:
    def test_controls_missing(self) -> None:
        """Framework exists in registry but has no controls YAML."""
        # iso27001 is in registry (pro tier) but has no controls file
        warnings = validate_framework_profile("iso27001", "gcp")
        assert len(warnings) >= 1
        assert "Controls" in warnings[0]


class TestValidateMappingsFailure:
    def test_mappings_missing(self, tmp_path: Path) -> None:
        """Controls exist but mappings for the cloud don't."""
        _reset_all()
        # soc2 has controls + gcp mappings, but no "oracle" cloud dir
        warnings = validate_framework_profile("soc2", "oracle")
        assert len(warnings) >= 1
        assert "Mappings" in warnings[0]


class TestValidateUnknownControlId:
    def test_mapping_references_bad_control(self, tmp_path: Path) -> None:
        """Mapping file references a control_id not in the controls file."""
        _reset_all()

        # Create a minimal controls file
        controls_dir = tmp_path / "controls"
        controls_dir.mkdir()
        (controls_dir / "test_fw.yaml").write_text(
            "schema_version: 1\n"
            "framework_id: test_fw\n"
            "framework_version: '1'\n"
            "controls:\n"
            "  - id: 'CTRL-1'\n"
            "    title: 'Only Control'\n"
        )

        # Create a mappings file referencing a nonexistent control
        gcp_dir = tmp_path / "mappings" / "gcp"
        gcp_dir.mkdir(parents=True)
        (gcp_dir / "test_fw.yaml").write_text(
            "schema_version: 1\n"
            "framework_id: test_fw\n"
            "cloud: gcp\n"
            "mappings:\n"
            "  - check_id: 'CKV_GCP_1'\n"
            "    control_id: 'CTRL-1'\n"
            "  - check_id: 'CKV_GCP_2'\n"
            "    control_id: 'NONEXISTENT'\n"
        )

        # Also need registry to have test_fw
        reg_dir = tmp_path
        (reg_dir / "framework_registry.yaml").write_text(
            "schema_version: 1\n"
            "frameworks:\n"
            "  - id: test_fw\n"
            "    name: Test\n"
            "    version: '1'\n"
            "    authority: Test\n"
            "    tier: community\n"
            "    cloud: all\n"
            "    category: global\n"
            "    control_count: 1\n"
        )

        with (
            patch(
                "complyform.core.profiles.registry._PROFILES_DIR",
                tmp_path,
            ),
            patch(
                "complyform.core.profiles.control_loader._PROFILES_DIR",
                tmp_path,
            ),
            patch(
                "complyform.core.profiles.mapping_loader._PROFILES_DIR",
                tmp_path,
            ),
        ):
            _reset_all()
            warnings = validate_framework_profile("test_fw", "gcp")
            assert len(warnings) == 1
            assert "NONEXISTENT" in warnings[0]
            assert "CKV_GCP_2" in warnings[0]
