"""
Tests for the Applicability Engine (Phase C2).

Tests the deterministic filtering logic for industry, company size,
and scope signals without requiring a database connection.
"""

import pytest

from services.applicability_engine import (
    _matches_company_size,
    _matches_industry,
    _matches_scope_signals,
    _parse_json_text,
)


# =============================================================================
# _parse_json_text
# =============================================================================


class TestParseJsonText:
    def test_none_returns_none(self):
        assert _parse_json_text(None) is None

    def test_valid_json_list(self):
        assert _parse_json_text('["all"]') == ["all"]

    def test_valid_json_list_multiple(self):
        result = _parse_json_text('["Telekommunikation", "Energie"]')
        assert result == ["Telekommunikation", "Energie"]

    def test_valid_json_dict(self):
        result = _parse_json_text('{"requires_any": ["uses_ai"]}')
        assert result == {"requires_any": ["uses_ai"]}

    def test_invalid_json_returns_none(self):
        assert _parse_json_text("not json") is None

    def test_empty_string_returns_none(self):
        assert _parse_json_text("") is None

    def test_already_list_passthrough(self):
        val = ["all"]
        assert _parse_json_text(val) == ["all"]

    def test_already_dict_passthrough(self):
        val = {"requires_any": ["uses_ai"]}
        assert _parse_json_text(val) == val

    def test_integer_returns_none(self):
        assert _parse_json_text(42) is None


# =============================================================================
# _matches_industry
# =============================================================================


class TestMatchesIndustry:
    def test_null_matches_any_industry(self):
        assert _matches_industry(None, "Telekommunikation") is True

    def test_all_matches_any_industry(self):
        assert _matches_industry('["all"]', "Telekommunikation") is True
        assert _matches_industry('["all"]', "Energie") is True

    def test_specific_industry_matches(self):
        assert _matches_industry(
            '["Telekommunikation", "Energie"]', "Telekommunikation"
        ) is True

    def test_specific_industry_no_match(self):
        assert _matches_industry(
            '["Telekommunikation", "Energie"]', "Gesundheitswesen"
        ) is False

    def test_malformed_json_matches(self):
        """Malformed data should be treated as 'applies to everyone'."""
        assert _matches_industry("not json", "anything") is True

    def test_all_with_other_industries(self):
        assert _matches_industry(
            '["all", "Telekommunikation"]', "Gesundheitswesen"
        ) is True


# =============================================================================
# _matches_company_size
# =============================================================================


class TestMatchesCompanySize:
    def test_null_matches_any_size(self):
        assert _matches_company_size(None, "medium") is True

    def test_all_matches_any_size(self):
        assert _matches_company_size('["all"]', "micro") is True
        assert _matches_company_size('["all"]', "enterprise") is True

    def test_specific_size_matches(self):
        assert _matches_company_size(
            '["medium", "large", "enterprise"]', "large"
        ) is True

    def test_specific_size_no_match(self):
        assert _matches_company_size(
            '["medium", "large", "enterprise"]', "small"
        ) is False

    def test_micro_excluded_from_nis2(self):
        """NIS2 typically requires medium+."""
        assert _matches_company_size(
            '["medium", "large", "enterprise"]', "micro"
        ) is False

    def test_malformed_json_matches(self):
        assert _matches_company_size("broken", "medium") is True


# =============================================================================
# _matches_scope_signals
# =============================================================================


class TestMatchesScopeSignals:
    def test_null_conditions_always_match(self):
        assert _matches_scope_signals(None, ["uses_ai"]) is True
        assert _matches_scope_signals(None, []) is True

    def test_empty_requires_any_matches(self):
        assert _matches_scope_signals('{"requires_any": []}', ["uses_ai"]) is True

    def test_no_requires_any_key_matches(self):
        assert _matches_scope_signals(
            '{"description": "some text"}', ["uses_ai"]
        ) is True

    def test_requires_any_with_matching_signal(self):
        conditions = '{"requires_any": ["uses_ai"], "description": "AI Act"}'
        assert _matches_scope_signals(conditions, ["uses_ai"]) is True

    def test_requires_any_with_no_matching_signal(self):
        conditions = '{"requires_any": ["uses_ai"], "description": "AI Act"}'
        assert _matches_scope_signals(
            conditions, ["third_country_transfer"]
        ) is False

    def test_requires_any_with_one_of_multiple_matching(self):
        conditions = '{"requires_any": ["uses_ai", "processes_health_data"]}'
        assert _matches_scope_signals(
            conditions, ["processes_health_data", "financial_data"]
        ) is True

    def test_requires_any_with_no_signals_provided(self):
        conditions = '{"requires_any": ["uses_ai"]}'
        assert _matches_scope_signals(conditions, []) is False

    def test_malformed_json_matches(self):
        assert _matches_scope_signals("broken", ["uses_ai"]) is True

    def test_multiple_required_signals_any_match(self):
        """requires_any means at least ONE must match."""
        conditions = (
            '{"requires_any": ["uses_ai", "third_country_transfer", '
            '"processes_health_data"]}'
        )
        assert _matches_scope_signals(
            conditions, ["third_country_transfer"]
        ) is True

    def test_multiple_required_signals_none_match(self):
        conditions = (
            '{"requires_any": ["uses_ai", "third_country_transfer"]}'
        )
        assert _matches_scope_signals(
            conditions, ["financial_data", "employee_monitoring"]
        ) is False


# =============================================================================
# Integration-style: combined filtering scenarios
# =============================================================================


class TestCombinedFiltering:
    """Test typical real-world filtering scenarios."""

    def test_dsgvo_art5_applies_to_everyone(self):
        """DSGVO Art. 5 = all industries, all sizes, no scope conditions."""
        assert _matches_industry('["all"]', "Telekommunikation") is True
        assert _matches_company_size('["all"]', "micro") is True
        assert _matches_scope_signals(None, []) is True

    def test_nis2_art21_kritis_medium_plus(self):
        """NIS2 Art. 21 = KRITIS sectors, medium+."""
        industries = '["Energie", "Gesundheitswesen", "Digitale Infrastruktur", "Logistik / Transport"]'
        sizes = '["medium", "large", "enterprise"]'

        # Matches: Energie + large
        assert _matches_industry(industries, "Energie") is True
        assert _matches_company_size(sizes, "large") is True

        # No match: IT company
        assert _matches_industry(industries, "Technologie / IT") is False

        # No match: small company
        assert _matches_company_size(sizes, "small") is False

    def test_ai_act_scope_condition(self):
        """AI Act = all industries, all sizes, but only if uses_ai."""
        conditions = '{"requires_any": ["uses_ai"], "description": "Nur bei KI-Einsatz"}'

        # Company uses AI
        assert _matches_scope_signals(conditions, ["uses_ai"]) is True

        # Company does not use AI
        assert _matches_scope_signals(conditions, []) is False
        assert _matches_scope_signals(
            conditions, ["third_country_transfer"]
        ) is False

    def test_tkg_telekom_only(self):
        """TKG = only Telekommunikation, all sizes."""
        industries = '["Telekommunikation"]'

        assert _matches_industry(industries, "Telekommunikation") is True
        assert _matches_industry(industries, "Energie") is False
