"""Tests for complyform.core.greenfield.config_merger — merge engine."""

from __future__ import annotations

from typing import Any

import pytest

from complyform.core.errors import ConfigMergeConflictError
from complyform.core.greenfield.config_merger import (
    STRICTNESS_ORDER,
    merge_required_configs,
)


class TestMergeBooleansTrueWins:
    def test_false_plus_true(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"deletion_protection": False}),
            ("hipaa", "164.312", {"deletion_protection": True}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["deletion_protection"] is True

    def test_true_plus_false(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"deletion_protection": True}),
            ("hipaa", "164.312", {"deletion_protection": False}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["deletion_protection"] is True


class TestMergeEnumsStrictestWins:
    def test_ssl_mode(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"ssl_mode": "ALLOW_UNENCRYPTED_AND_ENCRYPTED"}),
            ("hipaa", "164.312", {"ssl_mode": "ENCRYPTED_ONLY"}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["ssl_mode"] == "ENCRYPTED_ONLY"


class TestMergeNumericsMaxWins:
    def test_retention_days(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"retention_days": 90}),
            ("hipaa", "164.312", {"retention_days": 365}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["retention_days"] == 365


class TestMergeStringsIdenticalOk:
    def test_same_value(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"database_version": "POSTGRES_16"}),
            ("hipaa", "164.312", {"database_version": "POSTGRES_16"}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["database_version"] == "POSTGRES_16"


class TestMergeStringsConflict:
    def test_different_strings_raise(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"database_version": "POSTGRES_16"}),
            ("hipaa", "164.312", {"database_version": "MYSQL_8"}),
        ]
        with pytest.raises(ConfigMergeConflictError):
            merge_required_configs(configs)


class TestMergeDictsRecursive:
    def test_nested_merge(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"settings": {"backup": True}}),
            ("hipaa", "164.312", {"settings": {"ssl": True}}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["settings"]["backup"] is True
        assert merged["settings"]["ssl"] is True


class TestMergeListsUnion:
    def test_deduplicates(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"flags": ["a", "b"]}),
            ("hipaa", "164.312", {"flags": ["b", "c"]}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged["flags"] == ["a", "b", "c"]


class TestMergeGeneratesTrace:
    def test_trace_contains_all(self) -> None:
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("soc2", "CC6.1", {"x": 1}),
            ("hipaa", "164.312", {"y": 2}),
        ]
        _, trace = merge_required_configs(configs)
        assert "soc2.CC6.1" in trace
        assert "hipaa.164.312" in trace


class TestStrictnessOrderAllEnums:
    @pytest.mark.parametrize("key", list(STRICTNESS_ORDER.keys()))
    def test_strictest_wins(self, key: str) -> None:
        values = STRICTNESS_ORDER[key]
        strictest = values[0]
        least = values[-1]
        configs: list[tuple[str, str, dict[str, Any]]] = [
            ("fw1", "c1", {key: least}),
            ("fw2", "c2", {key: strictest}),
        ]
        merged, _ = merge_required_configs(configs)
        assert merged[key] == strictest
