"""
I1 ADR-064 get_incident_type() 整合測試
========================================
測試策略 (feedback_no_mock_testing.md):
- 直接呼叫 get_incident_type()，不 Mock YAML / 靜態 dict
- 驗證三層降級：YAML incident_type → 靜態 dict → "custom"
- 2026-04-11 Claude Sonnet 4.6: Code Review C1 修補
"""

import pytest

from src.constants.alert_types import ALERTNAME_TO_TYPE
from src.services.alert_rule_engine import get_incident_type


class TestGetIncidentTypeStaticFallback:
    """Layer 2: 靜態 dict fallback（YAML 無 incident_type 欄位時）"""

    def test_known_alertname_returns_static_dict_value(self):
        """HostHighCpuLoad → 靜態 dict 應回傳 host_cpu"""
        result = get_incident_type("HostHighCpuLoad")
        assert result == "host_cpu"

    def test_known_alertname_k8s(self):
        """KubePodCrashLooping → k8s_pod_crash"""
        result = get_incident_type("KubePodCrashLooping")
        assert result == "k8s_pod_crash"

    def test_known_alertname_database(self):
        """PostgreSQLDown → database_down"""
        result = get_incident_type("PostgreSQLDown")
        assert result == "database_down"

    def test_known_alertname_service(self):
        """SentryDown → service_down"""
        result = get_incident_type("SentryDown")
        assert result == "service_down"

    def test_known_alertname_ssl(self):
        """ExternalSiteSSLExpiringSoon → ssl_expiry"""
        result = get_incident_type("ExternalSiteSSLExpiringSoon")
        assert result == "ssl_expiry"


class TestGetIncidentTypeCustomFallback:
    """Layer 3: unknown alertname → "custom" """

    def test_unknown_alertname_returns_custom(self):
        result = get_incident_type("SomeCompletelyUnknownAlert")
        assert result == "custom"

    def test_empty_string_returns_custom(self):
        result = get_incident_type("")
        assert result == "custom"


class TestGetIncidentTypeYamlPriority:
    """Layer 1: YAML rule 有 incident_type 欄位時優先使用"""

    def test_yaml_incident_type_overrides_static_dict(self, tmp_path, monkeypatch):
        """若 YAML rule 明確設定 incident_type，應回傳 YAML 值（而非靜態 dict 值）"""
        import yaml
        from src.services import alert_rule_engine as engine

        yaml_content = {
            "version": "1.0.0",
            "rules": [
                {
                    "id": "test_rule",
                    "priority": 1,
                    "description": "test",
                    "match": {"alertname": ["HostHighCpuLoad"]},
                    "incident_type": "custom_cpu_override",
                    "response": {
                        "action_title": "test",
                        "suggested_action": "NO_ACTION",
                        "risk": "low",
                        "responsibility": "INFRA",
                        "responsibility_reasoning": "test",
                        "secondary_teams": [],
                        "reasoning": "test",
                    },
                }
            ],
        }
        rules_file = tmp_path / "alert_rules.yaml"
        rules_file.write_text(yaml.dump(yaml_content))

        # 替換 RULES_FILE 路徑並清除 lru_cache
        monkeypatch.setattr(engine, "RULES_FILE", rules_file)
        engine._load_rules.cache_clear()

        result = get_incident_type("HostHighCpuLoad")
        assert result == "custom_cpu_override"

        # 清理 cache，還原給後續測試
        engine._load_rules.cache_clear()

    def test_yaml_match_without_incident_type_falls_through_to_static(
        self, tmp_path, monkeypatch
    ):
        """YAML rule 匹配到 alertname 但無 incident_type 欄位 → 必須 fallthrough 到靜態 dict"""
        import yaml
        from src.services import alert_rule_engine as engine

        yaml_content = {
            "version": "1.0.0",
            "rules": [
                {
                    "id": "host_cpu",  # id 值與靜態 dict value 相同，但這是巧合，不應被依賴
                    "priority": 1,
                    "description": "test",
                    "match": {"alertname": ["HostHighCpuLoad"]},
                    # 故意不設 incident_type
                    "response": {
                        "action_title": "test",
                        "suggested_action": "NO_ACTION",
                        "risk": "low",
                        "responsibility": "INFRA",
                        "responsibility_reasoning": "test",
                        "secondary_teams": [],
                        "reasoning": "test",
                    },
                }
            ],
        }
        rules_file = tmp_path / "alert_rules.yaml"
        rules_file.write_text(yaml.dump(yaml_content))

        monkeypatch.setattr(engine, "RULES_FILE", rules_file)
        engine._load_rules.cache_clear()

        result = get_incident_type("HostHighCpuLoad")
        # 靜態 dict 應回傳 host_cpu（不應回傳 rule.id）
        assert result == ALERTNAME_TO_TYPE["HostHighCpuLoad"]
        assert result == "host_cpu"

        engine._load_rules.cache_clear()


class TestGetIncidentTypeYamlError:
    """YAML 載入失敗時應 graceful fallback"""

    def test_corrupted_yaml_falls_back_to_static(self, tmp_path, monkeypatch):
        from src.services import alert_rule_engine as engine

        rules_file = tmp_path / "alert_rules.yaml"
        rules_file.write_text("{{invalid yaml{{{{")

        monkeypatch.setattr(engine, "RULES_FILE", rules_file)
        engine._load_rules.cache_clear()

        result = get_incident_type("HostHighCpuLoad")
        assert result == "host_cpu"  # 靜態 dict fallback

        engine._load_rules.cache_clear()

    def test_missing_yaml_falls_back_to_static(self, tmp_path, monkeypatch):
        from src.services import alert_rule_engine as engine

        monkeypatch.setattr(engine, "RULES_FILE", tmp_path / "nonexistent.yaml")
        engine._load_rules.cache_clear()

        result = get_incident_type("KubeNodeNotReady")
        assert result == "k8s_node_failure"

        engine._load_rules.cache_clear()
