"""
Phase 19.6: Terminal Service Tests
==================================
Omni-Terminal SSE 架構測試

Phase 22 P1 修復: 移除 Mock，使用真實服務
2026-03-31 Claude Code (首席架構師)

測試內容:
1. 意圖分類 (classify_intent) - 純函數
2. Model 驗證 - 純 Pydantic
3. Service 依賴注入
4. 整合測試 (需要 Redis/K8s)

遵循規範:
- feedback_no_mock_testing.md: 禁止 MagicMock/AsyncMock/patch
- ADR-031 Omni-Terminal SSE Architecture
"""

import pytest

from src.models.terminal import (
    SpatialContext,
    TerminalIntentRequest,
    TerminalSessionStatus,
)
from src.services.terminal_service import (
    IntentType,
    TerminalService,
    classify_intent,
    get_terminal_service,
)


# =============================================================================
# Test Markers
# =============================================================================

requires_database = pytest.mark.skipif(
    "not config.getoption('--run-integration', default=False)",
    reason="Need --run-integration option to run database integration tests",
)

requires_k8s = pytest.mark.skipif(
    "not config.getoption('--run-k8s', default=False)",
    reason="Need --run-k8s option to run K8s integration tests",
)


# =============================================================================
# Intent Classification Tests - Pure Functions
# =============================================================================

INTENT_CLASSIFICATION_TEST_CASES = [
    # 查詢類 - 狀態
    ("status", IntentType.QUERY_STATUS),
    ("狀態", IntentType.QUERY_STATUS),
    ("pod status", IntentType.QUERY_STATUS),
    ("健康狀態", IntentType.QUERY_STATUS),
    ("health check", IntentType.QUERY_STATUS),

    # 查詢類 - 指標
    ("metrics", IntentType.QUERY_METRICS),
    ("指標", IntentType.QUERY_METRICS),
    ("cpu usage", IntentType.QUERY_METRICS),
    ("記憶體使用量", IntentType.QUERY_METRICS),
    ("memory utilization", IntentType.QUERY_METRICS),

    # 查詢類 - 日誌
    ("logs", IntentType.QUERY_LOGS),
    ("日誌", IntentType.QUERY_LOGS),
    ("error logs", IntentType.QUERY_LOGS),
    ("錯誤訊息", IntentType.QUERY_LOGS),
    ("exception trace", IntentType.QUERY_LOGS),

    # 操作類 - 簽核
    ("approve", IntentType.ACTION_APPROVAL),
    ("簽核", IntentType.ACTION_APPROVAL),
    ("授權", IntentType.ACTION_APPROVAL),
    ("批准這個操作", IntentType.ACTION_APPROVAL),
    ("show pending approval", IntentType.ACTION_APPROVAL),

    # 操作類 - 重啟
    ("restart", IntentType.ACTION_RESTART),
    ("重啟", IntentType.ACTION_RESTART),
    ("rollout", IntentType.ACTION_RESTART),
    ("重新部署", IntentType.ACTION_RESTART),

    # 操作類 - 擴容
    ("scale", IntentType.ACTION_SCALE),
    ("擴容", IntentType.ACTION_SCALE),
    ("增加副本", IntentType.ACTION_SCALE),
    ("replica count", IntentType.ACTION_SCALE),

    # 分析類 - RCA
    ("rca", IntentType.ANALYZE_RCA),
    ("root cause", IntentType.ANALYZE_RCA),
    ("根因", IntentType.ANALYZE_RCA),
    ("分析問題", IntentType.ANALYZE_RCA),
    ("為什麼 API 變慢", IntentType.ANALYZE_RCA),
    ("why is it slow", IntentType.ANALYZE_RCA),

    # 分析類 - Incident
    ("incident", IntentType.ANALYZE_INCIDENT),
    ("事件", IntentType.ANALYZE_INCIDENT),
    ("alert 告警", IntentType.ANALYZE_INCIDENT),
    ("告警詳情", IntentType.ANALYZE_INCIDENT),

    # 一般
    ("hello", IntentType.GENERAL),
    ("你好", IntentType.GENERAL),
    ("help", IntentType.GENERAL),
    ("random text", IntentType.GENERAL),
]


@pytest.mark.parametrize("intent,expected_type", INTENT_CLASSIFICATION_TEST_CASES)
def test_classify_intent(intent: str, expected_type: IntentType):
    """測試意圖分類準確度 - 純函數，不需要外部依賴"""
    result = classify_intent(intent)
    assert result == expected_type, f"Intent '{intent}' should be classified as {expected_type}, got {result}"


def test_classify_intent_case_insensitive():
    """測試意圖分類不區分大小寫"""
    assert classify_intent("STATUS") == IntentType.QUERY_STATUS
    assert classify_intent("Metrics") == IntentType.QUERY_METRICS
    assert classify_intent("RESTART") == IntentType.ACTION_RESTART


# =============================================================================
# Model Validation Tests - Pure Pydantic
# =============================================================================


def test_spatial_context_required_fields():
    """測試 SpatialContext 必填欄位"""
    context = SpatialContext(current_page="/dashboard")
    assert context.current_page == "/dashboard"
    assert context.focused_entity_id is None  # 預設為 None


def test_spatial_context_with_entity():
    """測試 SpatialContext 帶實體 ID"""
    context = SpatialContext(
        current_page="/incidents",
        focused_entity_id="INC-001",
    )
    assert context.current_page == "/incidents"
    assert context.focused_entity_id == "INC-001"


def test_terminal_intent_request_validation():
    """測試 TerminalIntentRequest 驗證"""
    request = TerminalIntentRequest(
        intent="check system status",
        context=SpatialContext(current_page="/dashboard"),
    )
    assert request.intent == "check system status"
    assert request.context.current_page == "/dashboard"
    assert request.session_id is None  # 預設為 None


def test_terminal_intent_request_with_session():
    """測試帶 session_id 的 TerminalIntentRequest"""
    request = TerminalIntentRequest(
        intent="continue analysis",
        context=SpatialContext(current_page="/"),
        session_id="sess-001",
    )
    assert request.session_id == "sess-001"


def test_terminal_session_status_enum():
    """測試 TerminalSessionStatus 枚舉值"""
    assert TerminalSessionStatus.PENDING.value == "pending"
    assert TerminalSessionStatus.PROCESSING.value == "processing"
    assert TerminalSessionStatus.COMPLETED.value == "completed"
    assert TerminalSessionStatus.ERROR.value == "error"
    assert TerminalSessionStatus.ABORTED.value == "aborted"


# =============================================================================
# Dependency Injection Tests
# =============================================================================


@pytest.mark.asyncio
async def test_get_terminal_service():
    """測試 FastAPI 依賴注入函數"""
    service = await get_terminal_service()
    assert isinstance(service, TerminalService)


@pytest.mark.asyncio
async def test_get_terminal_service_creates_new_instance():
    """測試每次呼叫建立新實例 (非 Singleton)"""
    service1 = await get_terminal_service()
    service2 = await get_terminal_service()
    assert service1 is not service2, "Should create new instance each time"


# =============================================================================
# Service Unit Tests (No External Dependencies)
# =============================================================================


@pytest.mark.asyncio
async def test_terminal_service_instantiation():
    """測試 TerminalService 實例化"""
    service = TerminalService()
    assert service._sessions == {}
    assert service._tasks == {}


@pytest.mark.asyncio
async def test_get_session_not_found():
    """測試取得不存在的 Session"""
    service = TerminalService()
    session = await service.get_session("nonexistent-session")
    assert session is None


@pytest.mark.asyncio
async def test_abort_session_not_found():
    """測試中斷不存在的 Session"""
    service = TerminalService()
    result = await service.abort_session("nonexistent-session")
    assert result is False


# =============================================================================
# Intent Coverage Statistics
# =============================================================================


def test_intent_type_coverage():
    """確保所有 IntentType 都有測試案例"""
    tested_types = {expected for _, expected in INTENT_CLASSIFICATION_TEST_CASES}
    all_types = set(IntentType)

    missing = all_types - tested_types
    assert not missing, f"Missing test cases for IntentType: {missing}"


# =============================================================================
# Integration Tests - Require Real Services
# =============================================================================
# Phase 22 P1 修復: 移除 Mock，使用真實服務
# 2026-03-31 Claude Code (首席架構師)
# =============================================================================


class TestHandleApprovalActionIntegration:
    """
    _handle_approval_action 整合測試

    需要:
    - PostgreSQL (ApprovalService)
    - Redis (SSE Publisher)
    """

    @pytest.mark.asyncio
    @requires_database
    async def test_approval_action_returns_pending_list(self):
        """
        測試查詢待簽核項目

        使用真實 ApprovalService 查詢資料庫
        """
        from src.services.approval_service import get_approval_service

        service = TerminalService()
        approval_service = get_approval_service()

        # 查詢真實的待簽核項目
        pending = await approval_service.get_pending_approvals()

        # 驗證返回格式
        assert isinstance(pending, list)

    @pytest.mark.asyncio
    @requires_database
    async def test_approval_service_connection(self):
        """測試 ApprovalService 連線"""
        from src.services.approval_service import get_approval_service

        service = get_approval_service()
        # 應該能成功取得服務實例
        assert service is not None


class TestHandleStatusQueryIntegration:
    """
    _handle_status_query 整合測試

    需要:
    - K8s 連線 (K8sRepository)
    """

    @pytest.mark.asyncio
    @requires_k8s
    async def test_k8s_repository_available(self):
        """測試 K8sRepository 連線"""
        from src.repositories.k8s_repository import get_k8s_repository

        repo = get_k8s_repository()
        is_available = await repo.is_available()

        # 如果 K8s 可用，應該返回 True
        # 如果在 Mock 模式，也應該返回 True
        assert isinstance(is_available, bool)

    @pytest.mark.asyncio
    @requires_k8s
    async def test_k8s_pod_status_summary(self):
        """測試 K8s Pod 狀態摘要"""
        from src.repositories.k8s_repository import get_k8s_repository

        repo = get_k8s_repository()
        if not await repo.is_available():
            pytest.skip("K8s not available")

        summary = await repo.get_pod_status_summary()

        # 驗證返回格式
        assert "total" in summary
        assert "running" in summary
        assert "pending" in summary
        assert "failed" in summary

    @pytest.mark.asyncio
    @requires_k8s
    async def test_k8s_list_deployments(self):
        """測試 K8s Deployment 列表"""
        from src.repositories.k8s_repository import get_k8s_repository

        repo = get_k8s_repository()
        if not await repo.is_available():
            pytest.skip("K8s not available")

        deployments = await repo.list_deployments()

        # 驗證返回格式
        assert isinstance(deployments, list)


class TestTerminalServiceIntegration:
    """
    TerminalService 完整整合測試

    需要:
    - Redis (SSE Publisher)
    - PostgreSQL (ApprovalService)
    """

    @pytest.mark.asyncio
    @requires_database
    async def test_terminal_service_with_real_publisher(self):
        """
        測試 TerminalService 搭配真實 SSE Publisher

        驗證:
        1. 能建立 Session
        2. 能發送 SSE 事件
        """
        from src.core.sse import get_sse_publisher

        service = TerminalService()
        publisher = get_sse_publisher()

        # 驗證 publisher 實例
        assert publisher is not None

    @pytest.mark.asyncio
    @requires_database
    async def test_process_intent_with_real_services(self):
        """
        測試意圖處理 (不含 SSE 輸出)

        驗證:
        1. 意圖分類正確
        2. Session 狀態正確
        """
        service = TerminalService()

        # 測試意圖分類
        intent_type = classify_intent("check status")
        assert intent_type == IntentType.QUERY_STATUS

        intent_type = classify_intent("show pending approvals")
        assert intent_type == IntentType.ACTION_APPROVAL
