"""
AlertGroupingService 單元測試
==============================
ADR-076: 告警聚合引擎 — 告警風暴防禦

🔴🔴 遵循「禁止 Mock 測試鐵律」
- build_group_key / GroupingResult 邏輯測試：純 Python，無需 Redis
- Redis 整合部分標記 @pytest.mark.integration，正常 CI 跳過

建立: 2026-04-14 (台北時區) Claude Haiku 4.5
"""

import pytest

from src.services.alert_grouping_service import (
    AlertGroupingService,
    GroupingResult,
    _decode_redis_member,
)


class TestBuildGroupKey:
    """測試聚合分組 key 生成邏輯"""

    def test_basic_key(self):
        """基本 alertname + namespace → group_key"""
        key = AlertGroupingService.build_group_key("PodCrashLoopBackOff", "awoooi-prod")
        assert key == "PodCrashLoopBackOff:awoooi-prod"

    def test_strips_numeric_suffix(self):
        """帶數字後綴的 alertname 應取前綴"""
        key = AlertGroupingService.build_group_key("PodCrashLoopBackOff-3", "awoooi-prod")
        assert key == "PodCrashLoopBackOff:awoooi-prod"

    def test_strips_long_numeric_suffix(self):
        """帶長數字後綴的 alertname 應取前綴"""
        key = AlertGroupingService.build_group_key("HostHighCpuLoad-1234567", "default")
        assert key == "HostHighCpuLoad:default"

    def test_same_prefix_same_key(self):
        """相同前綴、相同 namespace → 相同 group_key（聚合生效）"""
        key1 = AlertGroupingService.build_group_key("PodOOMKilled-1", "awoooi-prod")
        key2 = AlertGroupingService.build_group_key("PodOOMKilled-2", "awoooi-prod")
        key3 = AlertGroupingService.build_group_key("PodOOMKilled-3", "awoooi-prod")
        assert key1 == key2 == key3

    def test_different_namespace_different_key(self):
        """相同 alertname、不同 namespace → 不同 group_key"""
        key1 = AlertGroupingService.build_group_key("PodCrash", "awoooi-prod")
        key2 = AlertGroupingService.build_group_key("PodCrash", "awoooi-staging")
        assert key1 != key2

    def test_different_alertname_different_key(self):
        """不同 alertname、相同 namespace → 不同 group_key"""
        key1 = AlertGroupingService.build_group_key("PodCrash", "awoooi-prod")
        key2 = AlertGroupingService.build_group_key("HostHighCpu", "awoooi-prod")
        assert key1 != key2

    def test_empty_namespace(self):
        """namespace 為空字串時應正常處理"""
        key = AlertGroupingService.build_group_key("PodCrash", "")
        assert key == "PodCrash:"

    def test_no_suffix_unchanged(self):
        """無數字後綴的 alertname 應保持不變"""
        key = AlertGroupingService.build_group_key("HostHighCpuLoad", "default")
        assert key == "HostHighCpuLoad:default"


class TestGroupingResultDataclass:
    """測試 GroupingResult dataclass"""

    def test_child_alert(self):
        """子告警：is_grouped=True, is_parent=False"""
        result = GroupingResult(
            is_grouped=True,
            group_key="PodCrash:awoooi-prod",
            count=5,
            parent_fingerprint="fp-001",
            is_parent=False,
        )
        assert result.is_grouped is True
        assert result.is_parent is False
        assert result.count == 5

    def test_parent_alert(self):
        """父告警：is_grouped=False, is_parent=True"""
        result = GroupingResult(
            is_grouped=False,
            group_key="PodCrash:awoooi-prod",
            count=1,
            parent_fingerprint="fp-001",
            is_parent=True,
        )
        assert result.is_grouped is False
        assert result.is_parent is True

    def test_second_alert_is_now_grouped(self):
        """門檻為 2：第一張保留主卡，第二張同組告警開始收斂。"""
        result = GroupingResult(
            is_grouped=True,
            group_key="PodCrash:awoooi-prod",
            count=2,
            parent_fingerprint="fp-001",
            is_parent=False,
        )
        assert result.is_grouped is True

    def test_group_key_format(self):
        """group_key 格式應為 {alertname_prefix}:{namespace}"""
        result = GroupingResult(
            is_grouped=True,
            group_key="PodOOMKilled:awoooi-prod",
            count=4,
            parent_fingerprint=None,
            is_parent=False,
        )
        assert ":" in result.group_key
        parts = result.group_key.split(":")
        assert len(parts) == 2


class TestRedisMemberDecode:
    """測試 Redis zrange member 正規化。"""

    def test_decode_bytes_member(self):
        assert _decode_redis_member(b"fp-parent", "fallback") == "fp-parent"

    def test_decode_none_uses_fallback(self):
        assert _decode_redis_member(None, "fallback") == "fallback"


class TestAlertGroupingServiceConstants:
    """測試服務常量設定"""

    def test_window_seconds(self):
        """視窗應為 5 分鐘 (300 秒)"""
        assert AlertGroupingService.WINDOW_SECONDS == 300

    def test_group_threshold(self):
        """聚合閾值應為 2：保留第一張主卡，第二張同組告警開始收斂。"""
        assert AlertGroupingService.GROUP_THRESHOLD == 2

    def test_ttl_seconds(self):
        """TTL 應長於視窗"""
        assert AlertGroupingService.TTL_SECONDS > AlertGroupingService.WINDOW_SECONDS

    def test_redis_key_prefix(self):
        """Redis key 前綴應符合規範"""
        assert AlertGroupingService.PREFIX_WINDOW.startswith("alert_group:")
        assert AlertGroupingService.PREFIX_META.startswith("alert_group:")
