"""
P1-3: ApprovalRequestCreate 欄位對齊測試
=========================================
驗證 SignOz + GitHub Webhook 的 ApprovalRequestCreate 符合 ApprovalRequestBase schema

測試策略 (遵循 feedback_no_mock_testing.md):
- 直接測試 Pydantic Model 驗證
- 使用真實 Schema 驗證欄位
- 不使用 Mock

版本: v1.0
建立: 2026-03-29 (台北時區)
建立者: Claude Code (P1-3 Unit Test)
"""

import pytest
from pydantic import ValidationError

from src.models.approval import (
    ApprovalRequestCreate,
    BlastRadius,
    DataImpact,
    RiskLevel,
)

# =============================================================================
# Test: ApprovalRequestCreate Schema 驗證
# =============================================================================

class TestApprovalRequestCreateSchema:
    """測試 ApprovalRequestCreate 必填欄位"""

    def test_required_fields_present(self):
        """✅ 必填欄位: action, description, risk_level, requested_by"""
        request = ApprovalRequestCreate(
            action="Test Action",
            description="Test Description",
            risk_level=RiskLevel.MEDIUM,
            requested_by="test-webhook",
        )
        assert request.action == "Test Action"
        assert request.description == "Test Description"
        assert request.risk_level == RiskLevel.MEDIUM
        assert request.requested_by == "test-webhook"

    def test_missing_action_raises_error(self):
        """❌ 缺少 action 應拋出 ValidationError"""
        with pytest.raises(ValidationError) as exc_info:
            ApprovalRequestCreate(
                description="Test",
                risk_level=RiskLevel.MEDIUM,
                requested_by="test",
            )
        assert "action" in str(exc_info.value)

    def test_missing_description_raises_error(self):
        """❌ 缺少 description 應拋出 ValidationError"""
        with pytest.raises(ValidationError) as exc_info:
            ApprovalRequestCreate(
                action="Test",
                risk_level=RiskLevel.MEDIUM,
                requested_by="test",
            )
        assert "description" in str(exc_info.value)

    def test_missing_requested_by_raises_error(self):
        """❌ 缺少 requested_by 應拋出 ValidationError"""
        with pytest.raises(ValidationError) as exc_info:
            ApprovalRequestCreate(
                action="Test",
                description="Test",
                risk_level=RiskLevel.MEDIUM,
            )
        assert "requested_by" in str(exc_info.value)


# =============================================================================
# Test: BlastRadius Model 驗證
# =============================================================================

class TestBlastRadiusSchema:
    """測試 BlastRadius 是 Pydantic Model，不是 Enum"""

    def test_blast_radius_is_model(self):
        """✅ BlastRadius 是 BaseModel，可接受參數"""
        br = BlastRadius(
            affected_pods=1,
            estimated_downtime="0",
            related_services=["api"],
            data_impact=DataImpact.READ_ONLY,
        )
        assert br.affected_pods == 1
        assert br.estimated_downtime == "0"
        assert br.related_services == ["api"]
        assert br.data_impact == DataImpact.READ_ONLY

    def test_blast_radius_default_values(self):
        """✅ BlastRadius 有預設值"""
        br = BlastRadius()
        assert br.affected_pods == 0
        assert br.estimated_downtime == "0"
        assert br.related_services == []
        assert br.data_impact == DataImpact.NONE


# =============================================================================
# Test: SignOz Webhook ApprovalRequestCreate 格式
# =============================================================================

class TestSignOzWebhookApproval:
    """測試 SignOz Webhook 的 ApprovalRequestCreate 格式"""

    def test_signoz_approval_format(self):
        """✅ SignOz Webhook 應使用正確欄位格式"""
        # 模擬 signoz_webhook.py 的建立方式
        alert_name = "HighErrorRate"
        service_name = "api-service"
        description = "Error rate > 5%"

        request = ApprovalRequestCreate(
            action=f"SignOz Alert: {alert_name}",
            description=description,
            risk_level=RiskLevel.HIGH,
            blast_radius=BlastRadius(
                affected_pods=1,
                estimated_downtime="0",
                related_services=[service_name],
                data_impact=DataImpact.READ_ONLY,
            ),
            dry_run_checks=[],
            requested_by="signoz-webhook",
            metadata={
                "source": "signoz",
                "alert_name": alert_name,
                "labels": {"service": service_name},
            },
        )

        assert request.action == "SignOz Alert: HighErrorRate"
        assert request.description == description
        assert request.requested_by == "signoz-webhook"
        assert request.blast_radius.related_services == [service_name]
        assert request.metadata["source"] == "signoz"


# =============================================================================
# Test: GitHub Webhook ApprovalRequestCreate 格式
# =============================================================================

class TestGitHubWebhookApproval:
    """測試 GitHub Webhook 的 ApprovalRequestCreate 格式"""

    def test_github_ci_failure_approval_format(self):
        """✅ GitHub CI Failure 應使用正確欄位格式"""
        repo = "wooo-ai/awoooi"
        root_cause = "Build failed due to missing dependency"
        suggestion = "npm install missing-package"

        request = ApprovalRequestCreate(
            action=f"CI Failure Repair: {repo}",
            description=f"Root Cause: {root_cause}\nSuggestion: {suggestion}",
            risk_level=RiskLevel.MEDIUM,
            blast_radius=BlastRadius(
                affected_pods=1,
                estimated_downtime="~5min",
                related_services=[repo],
                data_impact=DataImpact.NONE,
            ),
            dry_run_checks=[],
            requested_by="github-webhook",
            metadata={
                "source": "github",
                "alert_type": "ci_failure_repair",
                "target_resource": repo,
                "namespace": "github-actions",
            },
        )

        assert request.action == f"CI Failure Repair: {repo}"
        assert "Root Cause:" in request.description
        assert request.requested_by == "github-webhook"
        assert request.metadata["source"] == "github"
        assert request.metadata["alert_type"] == "ci_failure_repair"

    def test_github_code_review_approval_format(self):
        """✅ GitHub Code Review 應使用正確欄位格式"""
        repo = "wooo-ai/awoooi"
        target = "src/main.py"

        request = ApprovalRequestCreate(
            action=f"Code Review Security: {repo}",
            description=f"Root Cause: Code review found security concerns in {target}",
            risk_level=RiskLevel.HIGH,
            blast_radius=BlastRadius(
                affected_pods=1,
                estimated_downtime="0",
                related_services=[repo],
                data_impact=DataImpact.READ_ONLY,
            ),
            dry_run_checks=[],
            requested_by="github-webhook",
            metadata={
                "source": "github",
                "alert_type": "code_review_security",
                "target": target,
            },
        )

        assert request.action == f"Code Review Security: {repo}"
        assert request.requested_by == "github-webhook"
        assert request.metadata["alert_type"] == "code_review_security"


# =============================================================================
# Test: Sentry Webhook ApprovalRequestCreate 格式 (參照用)
# =============================================================================

class TestSentryWebhookApproval:
    """測試 Sentry Webhook 的 ApprovalRequestCreate 格式 (已正確)"""

    def test_sentry_approval_format(self):
        """✅ Sentry Webhook 格式正確 (參照用)"""
        level = "error"
        culprit = "api.views.handler"
        project = "awoooi-api"

        request = ApprovalRequestCreate(
            action=f"Sentry {level.upper()} Alert: {culprit}",
            description="TypeError: Cannot read property 'x' of undefined",
            risk_level=RiskLevel.HIGH,
            blast_radius=BlastRadius(
                affected_pods=1,
                estimated_downtime="0",
                related_services=[project],
                data_impact=DataImpact.READ_ONLY,
            ),
            dry_run_checks=[],
            requested_by="sentry-webhook",
            metadata={
                "source": "sentry",
                "issue_id": "12345",
            },
        )

        assert request.action == "Sentry ERROR Alert: api.views.handler"
        assert request.requested_by == "sentry-webhook"


# =============================================================================
# Test: 錯誤欄位驗證 (Pydantic v2 預設忽略額外欄位)
# =============================================================================

class TestInvalidFieldsBehavior:
    """
    測試舊格式 (錯誤欄位) 行為

    注意: Pydantic v2 預設 extra='ignore'，額外欄位不會拋出錯誤
    但是缺少必填欄位仍會拋出 ValidationError
    """

    def test_action_type_without_action_raises_error(self):
        """❌ 只有 action_type 而沒有 action 會失敗 (缺少必填欄位)"""
        with pytest.raises(ValidationError) as exc_info:
            ApprovalRequestCreate(
                action_type="SignOz Alert",  # 錯誤: 這不是有效欄位
                description="Test",
                risk_level=RiskLevel.MEDIUM,
                requested_by="test",
                # 缺少 action (必填)
            )
        assert "action" in str(exc_info.value)

    def test_extra_fields_are_ignored(self):
        """✅ 額外欄位會被忽略 (Pydantic v2 預設行為)"""
        # 這不會拋出錯誤，額外欄位會被忽略
        request = ApprovalRequestCreate(
            action="Test",
            description="Test",
            risk_level=RiskLevel.MEDIUM,
            requested_by="test",
            target_resource="api-service",  # 額外欄位，會被忽略
            context={"key": "value"},  # 額外欄位，會被忽略
        )
        # 驗證 request 物件沒有這些屬性
        assert not hasattr(request, "target_resource")
        assert not hasattr(request, "context")
        # 但必填欄位存在
        assert request.action == "Test"
        assert request.requested_by == "test"

    def test_metadata_is_valid_field(self):
        """✅ metadata 是有效欄位 (context 應改用 metadata)"""
        request = ApprovalRequestCreate(
            action="Test",
            description="Test",
            risk_level=RiskLevel.MEDIUM,
            requested_by="test",
            metadata={"key": "value"},  # 正確欄位
        )
        assert request.metadata == {"key": "value"}
