from __future__ import annotations

"""
AWOOOI API - SignOz Webhook Handler
====================================
接收 SignOz Alert，建立 Incident 並發送 Telegram 通知

整合流程:
1. SignOz Alert → AWOOOI API Webhook
2. 記錄異常頻率 (AnomalyCounter - ADR-037)
3. 建立 Incident (雙層記憶寫入)
4. 建立 Approval 供人工審核
5. 發送 Telegram 告警

🔴 HARD RULE: 時間顯示使用 Asia/Taipei (UTC+8)
"""

import uuid

import structlog
from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
from pydantic import BaseModel

from src.core.metrics import (
    record_alert_chain_failure,
    record_alert_chain_success,
    record_alert_processed,
    record_anomaly,
)
from src.models.approval import (
    ApprovalRequestCreate,
    BlastRadius,
    DataImpact,
    RiskLevel,
)
from src.services.anomaly_counter import get_anomaly_counter
from src.services.approval_db import get_approval_service
from src.services.incident_service import get_incident_service
from src.services.telegram_gateway import get_telegram_gateway
from src.utils.timezone import now_taipei_iso

logger = structlog.get_logger(__name__)

router = APIRouter(prefix="/webhooks/signoz", tags=["SignOz Webhook"])


# SignOz Severity → Risk Level 映射
SIGNOZ_SEVERITY_TO_RISK = {
    "critical": RiskLevel.CRITICAL,
    "error": RiskLevel.HIGH,
    "warning": RiskLevel.MEDIUM,
    "info": RiskLevel.LOW,
}


class SignOzAlertPayload(BaseModel):
    """SignOz Alert Payload (標準 Prometheus AlertManager 格式)"""

    alertname: str
    status: str  # firing, resolved
    labels: dict = {}
    annotations: dict = {}
    startsAt: str | None = None
    endsAt: str | None = None
    generatorURL: str | None = None


@router.post("/alert")
async def handle_signoz_alert(
    request: Request,
    background_tasks: BackgroundTasks,
):
    """
    SignOz 告警 Webhook Handler

    觸發條件:
    - Alert status=firing

    處理流程:
    1. 記錄異常頻率 (AnomalyCounter)
    2. 建立 Incident
    3. 建立 Approval
    4. 發送 Telegram 告警
    """
    try:
        payload = await request.json()
        logger.info("signoz_alert_received", payload=payload)

        # 解析 payload (支援陣列或單一告警)
        alerts = payload.get("alerts", [payload]) if isinstance(payload, dict) else [payload]

        results = []
        for alert in alerts:
            # 只處理 firing 狀態
            status = alert.get("status", "firing")
            if status != "firing":
                results.append({"status": "ignored", "reason": "not firing"})
                continue

            # 提取告警資訊
            alert_name = alert.get("alertname", alert.get("labels", {}).get("alertname", "unknown"))
            labels = alert.get("labels", {})
            annotations = alert.get("annotations", {})
            severity = labels.get("severity", "warning")

            # 背景處理
            background_tasks.add_task(
                process_signoz_alert,
                alert_name=alert_name,
                labels=labels,
                annotations=annotations,
                severity=severity,
                starts_at=alert.get("startsAt"),
            )

            results.append({
                "status": "accepted",
                "alert_name": alert_name,
            })

        return {"status": "ok", "processed": len(results), "results": results}

    except Exception as e:
        logger.exception("signoz_webhook_error", error=str(e))
        raise HTTPException(status_code=500, detail=str(e)) from e


async def process_signoz_alert(
    alert_name: str,
    labels: dict,
    annotations: dict,
    severity: str,
    starts_at: str | None,
):
    """
    背景處理 SignOz 告警

    ADR-037 Phase 21: 完整告警處理流程
    1. 記錄異常頻率
    2. 建立 Incident
    3. 呼叫 OpenClaw AI 進行 RCA 分析 (Nemo-4B 優先)
    4. 建立 Approval (帶入 AI 建議)
    5. 發送 Telegram (帶入 AI 信心度)
    """
    try:
        from src.services.openclaw import get_openclaw
        openclaw = get_openclaw()
        # =================================================================
        # Step 1: 記錄異常頻率 (ADR-037)
        # =================================================================
        anomaly_counter = get_anomaly_counter()
        anomaly_signature = {
            "alert_name": alert_name,
            "service": labels.get("service_name", labels.get("service", "unknown")),
            "namespace": labels.get("namespace", "signoz"),
            "error_type": labels.get("error_type", severity),
        }
        frequency = await anomaly_counter.record_anomaly(anomaly_signature)
        # 2026-03-31 ogt: AnomalyFrequency 是 dataclass，使用 to_dict() 而非 model_dump()
        anomaly_frequency = frequency.to_dict() if frequency else None

        logger.info(
            "signoz_anomaly_recorded",
            alert_name=alert_name,
            count_24h=frequency.count_24h if frequency else 0,
            escalation_level=frequency.escalation_level if frequency else None,
        )

        # Wave A.5: 記錄異常指標 (ADR-037)
        if frequency:
            record_anomaly(
                alert_name=alert_name,
                service=labels.get("service_name", labels.get("service", "unknown")),
                frequency_24h=frequency.count_24h,
                escalation_level=frequency.escalation_level,
            )

        # =================================================================
        # Step 2: 建立 Incident
        # =================================================================
        incident_service = get_incident_service()
        signal_data = {
            "alert_name": alert_name,
            "severity": severity,
            "source": "signoz",
            "target": labels.get("service_name", labels.get("service", "unknown")),
            "labels": labels,
            "annotations": annotations,
            "fingerprint": f"signoz-{alert_name}-{labels.get('service_name', 'unknown')}",
        }
        # ADR-037: 傳遞頻率統計到 Incident
        incident = await incident_service.create_incident_from_signal(
            signal_data, frequency_stats=anomaly_frequency
        )

        if not incident:
            logger.error("signoz_incident_creation_failed", alert_name=alert_name)
            return

        # =================================================================
        # Step 3: 呼叫 OpenClaw AI 進行 RCA 分析
        # =================================================================
        alert_context = {
            "alert_type": alert_name,
            "severity": severity,
            "target_resource": labels.get("service_name", labels.get("service", "unknown")),
            "namespace": labels.get("namespace", "default"),
            "message": annotations.get("description", annotations.get("summary", "")),
            "fingerprint": f"signoz-{alert_name}-{labels.get('service_name', 'unknown')}",
            "anomaly_frequency": anomaly_frequency,
        }

        # 這裡會呼叫 NVIDIA Nemo -> Gemini -> Ollama 鏈路
        analysis_result, ai_provider, raw_response, signoz_metrics, trace_url, tokens, cost = await openclaw.analyze_alert(
            alert_context
        )

        # =================================================================
        # Step 4: 建立 Approval
        # =================================================================
        approval_id = await create_signoz_approval(
            alert_name=alert_name,
            labels=labels,
            annotations=annotations,
            severity=severity,
            incident_id=incident.incident_id,
            anomaly_frequency=anomaly_frequency,
            analysis_result=analysis_result,  # 帶入 AI 結果
        )

        # =================================================================
        # Step 5: 發送 Telegram 告警
        # =================================================================
        await send_signoz_telegram(
            approval_id=approval_id,
            alert_name=alert_name,
            labels=labels,
            annotations=annotations,
            severity=severity,
            anomaly_frequency=anomaly_frequency,
            analysis_result=analysis_result,  # 帶入 AI 結果
            ai_provider=ai_provider,
        )

        logger.info(
            "signoz_alert_processed",
            alert_name=alert_name,
            incident_id=incident.incident_id,
            approval_id=approval_id,
        )

        # Wave A.5: 記錄告警鏈路成功 (ADR-037)
        record_alert_chain_success("signoz")
        record_alert_processed(
            source="signoz",
            severity=severity,
            outcome="incident_created",
        )

    except Exception as e:
        logger.exception("signoz_process_error", error=str(e), alert_name=alert_name)
        # Wave A.5: 記錄告警鏈路失敗 (ADR-037)
        record_alert_chain_failure("signoz")


async def create_signoz_approval(
    alert_name: str,
    labels: dict,
    annotations: dict,
    severity: str,
    incident_id: str,
    anomaly_frequency: dict | None = None,
    analysis_result: "LLMAnalysisResult" | None = None,
) -> str:
    """
    為 SignOz 告警建立 Approval 記錄

    ADR-037: 含異常頻率統計
    """
    try:
        approval_service = get_approval_service()

        # 決定風險等級 (考慮頻率升級)
        risk_level = SIGNOZ_SEVERITY_TO_RISK.get(severity, RiskLevel.MEDIUM)

        # ADR-037: 根據頻率升級風險等級
        if anomaly_frequency:
            escalation = anomaly_frequency.get("escalation_level")
            if escalation == "PERMANENT_FIX":
                risk_level = RiskLevel.CRITICAL
            elif escalation == "ESCALATE":
                risk_level = max(risk_level, RiskLevel.HIGH)

        # 建立 Approval
        service_name = labels.get("service_name", labels.get("service", "unknown"))
        summary = (
            analysis_result.action_title
            if analysis_result
            else annotations.get("summary", f"SignOz Alert: {alert_name}")
        )
        description = (
            analysis_result.description
            if analysis_result
            else annotations.get("description", summary)
        )

        # Step 4.2: 決定建議動作與指令
        action = summary
        command = ""
        if analysis_result:
            command = analysis_result.kubectl_command
            # 如果 AI 建議重啟但 annotations 有不同建議，以 AI 為準
            action = f"[AI 建議] {analysis_result.action_title}"
        else:
            action = f"SignOz Alert: {alert_name}"
        approval_request = ApprovalRequestCreate(
            action=action,
            description=description,
            risk_level=analysis_result.risk_level if analysis_result else risk_level,
            blast_radius=analysis_result.blast_radius if analysis_result else BlastRadius(
                affected_pods=1,
                estimated_downtime="0",
                related_services=[service_name],
                data_impact=DataImpact.READ_ONLY,
            ),
            kubectl_command=command,
            dry_run_checks=[],
            requested_by="signoz-webhook",
            metadata={
                "source": "signoz",
                "alert_name": alert_name,
                "labels": labels,
                "annotations": annotations,
                "incident_id": incident_id,
                "anomaly_frequency": anomaly_frequency,
                "ai_analyzed": analysis_result is not None,
            },
        )

        approval = await approval_service.create_approval(approval_request)
        return str(approval.id)

    except Exception as e:
        logger.exception("signoz_approval_error", error=str(e))
        # 回傳臨時 ID，不中斷流程
        return str(uuid.uuid4())


async def send_signoz_telegram(
    approval_id: str,
    alert_name: str,
    labels: dict,
    annotations: dict,
    severity: str,
    anomaly_frequency: dict | None = None,
    analysis_result: "LLMAnalysisResult" | None = None,
    ai_provider: str = "none",
):
    """
    發送 SignOz 告警到 Telegram

    ADR-037: 含異常頻率顯示
    """
    try:
        telegram = get_telegram_gateway()
        await telegram.initialize()

        service_name = labels.get("service_name", labels.get("service", "unknown"))
        summary = annotations.get("summary", f"SignOz Alert: {alert_name}")
        description = annotations.get("description", "")

        await telegram.send_approval_card(
            approval_id=approval_id,
            risk_level=analysis_result.risk_level if analysis_result else (
                "critical" if severity == "critical" else (
                    "high" if severity == "error" else "medium"
                )
            ),
            resource_name=service_name,
            root_cause=analysis_result.description if analysis_result else summary,
            suggested_action=analysis_result.action_title if analysis_result else (
                description or "請檢查 SignOz 儀表板"
            ),
            primary_responsibility=analysis_result.primary_responsibility if analysis_result else "BE",
            confidence=analysis_result.confidence if analysis_result else 0.0,
            namespace=labels.get("namespace", "signoz"),
            anomaly_frequency=anomaly_frequency,
        )

        logger.info(
            "signoz_telegram_sent",
            approval_id=approval_id,
            alert_name=alert_name,
            escalation_level=anomaly_frequency.get("escalation_level") if anomaly_frequency else None,
        )

    except Exception as e:
        logger.exception("signoz_telegram_error", error=str(e))


# =============================================================================
# Health Check (供 SignOz 確認 Webhook 可達)
# =============================================================================

@router.get("/health")
async def signoz_webhook_health():
    """SignOz Webhook 健康檢查"""
    return {
        "status": "ok",
        "service": "signoz-webhook",
        "timestamp": now_taipei_iso(),
    }
