"""
Incident API Endpoints - Phase 6.4 決策輸出層
=============================================

Endpoints:
- GET  /api/v1/incidents                     - 取得事件清單
- GET  /api/v1/incidents/{incident_id}       - 取得單一事件
- POST /api/v1/incidents/{incident_id}/proposal - 生成決策提案

Phase 6.4 核心功能:
1. 從 Incident 生成 Decision Proposal
2. 向下相容現有 ApprovalRequest 格式
3. 前端零改動即可渲染

統帥鐵律:
- 所有決策必須經過 TrustEngine 評估
- Proposal 必須關聯到 Incident
"""

from typing import Any

from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel, Field

from src.core.logging import get_logger
from src.models.approval import ApprovalRequestResponse
from src.models.incident import Incident, IncidentStatus, Severity

# Phase 22 P1: 移除 Repository 直接存取 (2026-03-31)
# Phase 16 R3.3b (2026-03-25 台北時區): Repository 層整合 - 已移至 Service 層
from src.services.decision_manager import get_decision_manager
from src.services.incident_service import get_incident_service
from src.services.proposal_service import get_proposal_service
from src.utils.timezone import now_taipei

router = APIRouter(prefix="/incidents", tags=["Incidents"])
logger = get_logger("awoooi.incidents")


# =============================================================================
# Response Models
# =============================================================================

class DecisionInfo(BaseModel):
    """Phase 6.5: 決策令牌資訊"""
    token: str
    state: str  # init, analyzing, ready, executing, completed
    proposal_data: dict[str, Any] | None = None
    proposal_id: str | None = None


class IncidentResponse(BaseModel):
    """事件回應 - Phase 6.5 含決策令牌"""
    incident_id: str
    status: str
    severity: str
    signal_count: int
    affected_services: list[str]
    proposal_count: int
    created_at: str
    updated_at: str
    # Phase 6.5: 決策令牌 (確保 UI 永不鎖死)
    decision: DecisionInfo | None = None

    @classmethod
    def from_incident(cls, incident: Incident, decision: DecisionInfo | None = None) -> "IncidentResponse":
        return cls(
            incident_id=incident.incident_id,
            status=incident.status.value,
            severity=incident.severity.value,
            signal_count=len(incident.signals),
            affected_services=incident.affected_services,
            proposal_count=len(incident.proposal_ids),
            created_at=incident.created_at.isoformat(),
            updated_at=incident.updated_at.isoformat(),
            decision=decision,
        )


class IncidentListResponse(BaseModel):
    """事件清單回應"""
    count: int
    incidents: list[IncidentResponse]


class ProposalGenerateResponse(BaseModel):
    """Proposal 生成回應"""
    success: bool
    message: str
    incident_id: str
    proposal: ApprovalRequestResponse | None = None
    incident_status: str | None = None


# =============================================================================
# GET /api/v1/incidents
# =============================================================================

@router.get(
    "",
    response_model=IncidentListResponse,
    summary="取得事件清單",
    description="""
    取得所有活躍事件 (INVESTIGATING 或 MITIGATING 狀態)。

    Phase 6.5 升級:
    - 每個事件自動附帶 decision_token
    - 確保 UI 永遠有決策可操作
    - 雙軌引擎: LLM (主) + Expert System (備)
    """,
)
async def list_incidents() -> IncidentListResponse:
    """
    取得活躍事件清單

    Phase 6.5: 自動為每個事件生成決策令牌
    - P0/P1 事件優先處理
    - 30 秒內保證有決策
    - LLM 失敗時 Expert System 保底

    Returns:
        IncidentListResponse: 事件清單與計數 (含決策令牌)
    """
    # Phase 17 P0: Router 層違規修復 - 改用 Service 層
    incident_service = get_incident_service()
    decision_manager = get_decision_manager()

    try:
        # 透過 Service 取得活躍事件
        incidents = await incident_service.get_active_incidents()

        # 按時間排序 (最新優先)
        # 2026-03-26 修復: 處理 timezone-aware 與 naive datetime 混合問題
        from datetime import UTC

        def safe_created_at(i: Incident) -> float:
            """安全取得 timestamp，處理 timezone 混合問題"""
            dt = i.created_at
            if dt.tzinfo is None:
                # naive datetime 假設為 UTC
                dt = dt.replace(tzinfo=UTC)
            return dt.timestamp()

        incidents.sort(key=safe_created_at, reverse=True)

        # Phase 6.5: 為每個事件生成決策令牌 (非同步並行)
        responses = []
        for incident in incidents:
            try:
                # P0/P1 給更短的 timeout (緊急)
                # 2026-03-27 ogt: 增加超時 (Ollama CPU 模式 llama3.2:3b 約 2-3 分鐘)
                timeout = 120.0 if incident.severity in (Severity.P0, Severity.P1) else 180.0

                decision_token = await decision_manager.get_or_create_decision(
                    incident=incident,
                    timeout_sec=timeout,
                )

                decision_info = DecisionInfo(
                    token=decision_token.token,
                    state=decision_token.state.value,
                    proposal_data=decision_token.proposal_data,
                    proposal_id=decision_token.proposal_id,
                )

                responses.append(IncidentResponse.from_incident(incident, decision_info))

            except Exception as e:
                logger.warning(
                    "decision_generation_failed",
                    incident_id=incident.incident_id,
                    error=str(e),
                )
                # 即使決策生成失敗，也返回事件 (不含 decision)
                responses.append(IncidentResponse.from_incident(incident, None))

        logger.info(
            "incidents_listed",
            count=len(incidents),
            with_decisions=sum(1 for r in responses if r.decision is not None),
        )

        return IncidentListResponse(
            count=len(incidents),
            incidents=responses,
        )

    except Exception as e:
        logger.exception(
            "list_incidents_error",
            error=str(e),
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to list incidents: {str(e)}",
        ) from e


# =============================================================================
# GET /api/v1/incidents/{incident_id}
# =============================================================================

@router.get(
    "/{incident_id}",
    response_model=IncidentResponse,
    summary="取得單一事件",
    description="取得特定事件的詳細資訊。",
)
async def get_incident(incident_id: str) -> IncidentResponse:
    """
    取得單一事件

    Args:
        incident_id: 事件 ID

    Returns:
        IncidentResponse: 事件詳細資訊

    Raises:
        HTTPException: 404 事件不存在
    """
    # Phase 17 P0: Router 層違規修復 - 改用 Service 層
    incident_service = get_incident_service()

    try:
        incident = await incident_service.get_from_working_memory(incident_id)
        if incident is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Incident not found: {incident_id}",
            )

        logger.info(
            "incident_fetched",
            incident_id=incident_id,
            status=incident.status.value,
        )

        return IncidentResponse.from_incident(incident)

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(
            "get_incident_error",
            incident_id=incident_id,
            error=str(e),
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get incident: {str(e)}",
        ) from e


# =============================================================================
# POST /api/v1/incidents/{incident_id}/proposal
# =============================================================================

@router.post(
    "/{incident_id}/proposal",
    response_model=ProposalGenerateResponse,
    summary="生成決策提案",
    description="""
    根據 Incident 生成 Decision Proposal。

    流程:
    1. 分析 Incident 的 signals 決定修復動作
    2. 透過 TrustEngine 評估風險等級
    3. 建立 ApprovalRequest (向下相容前端)
    4. 關聯 Proposal 到 Incident
    5. 推進 Incident 狀態為 MITIGATING

    生成的 Proposal 會出現在 /api/v1/approvals/pending 清單中，
    前端無需任何改動即可渲染。
    """,
)
async def generate_proposal(incident_id: str) -> ProposalGenerateResponse:
    """
    從 Incident 生成 Decision Proposal

    Args:
        incident_id: 事件 ID

    Returns:
        ProposalGenerateResponse: 生成結果

    Raises:
        HTTPException: 404 事件不存在, 400 無法生成
    """
    service = get_proposal_service()
    approval, message = await service.generate_proposal(incident_id)

    if approval is None:
        if "not found" in message.lower():
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=message,
            )
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=message,
        )

    logger.info(
        "proposal_generated",
        incident_id=incident_id,
        approval_id=str(approval.id),
        risk_level=approval.risk_level.value,
    )

    # Phase 17 P0: 改用 Service 層取得狀態
    incident_service = get_incident_service()
    incident_status = None
    try:
        incident = await incident_service.get_from_working_memory(incident_id)
        if incident:
            incident_status = incident.status.value
    except Exception:
        pass

    return ProposalGenerateResponse(
        success=True,
        message=message,
        incident_id=incident_id,
        proposal=ApprovalRequestResponse.from_approval(approval),
        incident_status=incident_status,
    )


# =============================================================================
# PUT /api/v1/incidents/{incident_id}/feedback - Phase 6.6 人類回饋 API
# =============================================================================


class FeedbackRequest(BaseModel):
    """人類回饋請求"""

    effectiveness_score: int | None = Field(
        None,
        ge=1,
        le=5,
        description="有效性評分 (1-5 分, 5 最有效)",
    )
    human_feedback: str | None = Field(
        None,
        max_length=1000,
        description="文字回饋 (如 '這個建議很準' 或 '下次應該先檢查 X')",
    )
    learning_notes: str | None = Field(
        None,
        max_length=2000,
        description="給未來 AI 的學習筆記",
    )
    should_remember: bool = Field(
        default=True,
        description="是否納入長期記憶 (Episodic Memory)",
    )


class FeedbackResponse(BaseModel):
    """人類回饋回應"""

    success: bool
    message: str
    incident_id: str
    outcome: dict[str, Any] | None = None


@router.put(
    "/{incident_id}/feedback",
    response_model=FeedbackResponse,
    summary="提交人類回饋",
    description="""
    Phase 6.6: 人類回饋 API

    用途:
    - 收集人類對 AI 建議的有效性評分
    - 記錄文字回饋與學習筆記
    - 作為 AI 改進的訓練數據

    工作流程:
    1. 更新 Incident 的 outcome 欄位
    2. 同步到 Redis (Working Memory) 和 PostgreSQL (Episodic Memory)
    3. 供統計分析 API (/api/v1/stats/feedback/summary) 聚合查詢
    """,
)
async def submit_feedback(
    incident_id: str,
    request: FeedbackRequest,
) -> FeedbackResponse:
    """
    提交人類對 AI 建議的回饋

    Args:
        incident_id: 事件 ID
        request: 回饋內容

    Returns:
        FeedbackResponse: 更新結果

    Raises:
        HTTPException: 404 事件不存在
    """
    # Phase 17 P0: Router 層違規修復 - 改用 Service 層
    incident_service = get_incident_service()

    try:
        incident = await incident_service.update_outcome(
            incident_id=incident_id,
            effectiveness_score=request.effectiveness_score,
            human_feedback=request.human_feedback,
            learning_notes=request.learning_notes,
            should_remember=request.should_remember,
        )

        if incident is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Incident not found: {incident_id}",
            )

        logger.info(
            "feedback_updated",
            incident_id=incident_id,
            effectiveness_score=request.effectiveness_score,
        )

        return FeedbackResponse(
            success=True,
            message="Feedback submitted successfully",
            incident_id=incident_id,
            outcome=incident.outcome.model_dump(mode="json") if incident.outcome else {},
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception("feedback_update_error", incident_id=incident_id)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update feedback: {str(e)}",
        ) from e


# =============================================================================
# DEBUG: 測試 Incident 狀態更新
# =============================================================================

@router.post(
    "/{incident_id}/resolve",
    summary="[DEBUG] 直接將 Incident 標記為 RESOLVED",
    description="測試用端點，直接更新 Incident 狀態",
)
async def debug_resolve_incident(incident_id: str) -> dict[str, Any]:
    """
    DEBUG: 直接更新 Incident 狀態為 RESOLVED
    用於測試 resolve_incident_after_approval 邏輯

    Phase 22 P1: Router 層違規修復 - 完全使用 Service 層 (2026-03-31)
    """
    incident_service = get_incident_service()
    error_msg = None

    # 1. 取得更新前狀態 (透過 Service)
    before_status = None
    try:
        incident = await incident_service.get_from_working_memory(incident_id)
        if incident:
            before_status = incident.status.value
    except Exception as e:
        error_msg = f"Read error: {e}"

    # 2. 透過 Service 更新狀態
    updated = False
    try:
        resolved = await incident_service.resolve_incident(incident_id)
        if resolved:
            updated = True
    except Exception as e:
        error_msg = f"Resolve error: {e}"

    # 3. 驗證更新後狀態 (透過 Service)
    after_status = None
    try:
        incident = await incident_service.get_from_working_memory(incident_id)
        if incident:
            after_status = incident.status.value
    except Exception:
        pass

    return {
        "incident_id": incident_id,
        "before_status": before_status,
        "after_status": after_status,
        "updated": updated,
        "error": error_msg,
    }


# =============================================================================
# POST /api/v1/incidents/sync-from-approvals - 補建 Incidents
# =============================================================================

class SyncResult(BaseModel):
    """同步結果"""
    synced: int
    skipped: int
    errors: list[str]
    details: list[dict[str, Any]]


@router.post(
    "/sync-from-approvals",
    response_model=SyncResult,
    summary="從現有 Approvals 補建 Incidents",
    description="""
    修復歷史數據：為沒有對應 Incident 的 Approvals 補建。

    用途：
    - 修復 b645981 之前創建的 Approvals（無 Incident）
    - 確保「活躍事件」與「待簽核」數量一致
    """,
)
async def sync_incidents_from_approvals() -> SyncResult:
    """
    掃描所有 pending Approvals，為缺少 Incident 的補建

    Phase 17 P0: Router 層違規修復 - 改用 Service 層
    """
    from uuid import UUID

    from src.models.incident import Signal
    from src.services.approval_db import get_approval_service

    # Phase 17 P0: 改用 Service 層
    incident_service = get_incident_service()
    approval_service = get_approval_service()

    synced = 0
    skipped = 0
    errors: list[str] = []
    details: list[dict[str, Any]] = []

    # 取得所有 pending approvals
    pending_approvals = await approval_service.get_pending_approvals()

    for approval in pending_approvals:
        approval_id = str(approval.id)

        # Phase 17 P0: 透過 Service 查找關聯 Incident
        existing = await incident_service.find_by_proposal_id(approval_id)
        if existing:
            skipped += 1
            continue

        # 補建 Incident
        try:
            # 映射 risk_level -> severity
            risk_map = {
                "critical": Severity.P0,
                "high": Severity.P1,
                "medium": Severity.P2,
                "low": Severity.P3,
            }
            severity = risk_map.get(approval.risk_level.value.lower(), Severity.P2)

            # 解析 action 取得資源名稱
            action_parts = approval.action.split("|")
            resource_name = action_parts[0].strip() if action_parts else "unknown"

            signal = Signal(
                alert_name="sync_from_approval",
                severity=severity,
                source="backfill",
                fired_at=approval.created_at,
                labels={"approval_id": approval_id},
                annotations={"description": approval.description or ""},
            )

            incident = Incident(
                status=IncidentStatus.INVESTIGATING,
                severity=severity,
                signals=[signal],
                affected_services=[resource_name],
                proposal_ids=[UUID(approval_id)],
                created_at=approval.created_at,
                updated_at=now_taipei(),
            )

            # Phase 17 P0: 透過 Service 儲存
            saved = await incident_service.save_to_working_memory(incident)
            if not saved:
                errors.append(f"Failed to save incident for approval {approval_id}")
                continue

            synced += 1
            details.append({
                "approval_id": approval_id,
                "incident_id": incident.incident_id,
                "severity": severity.value,
            })

            logger.info(
                "incident_synced_from_approval",
                approval_id=approval_id,
                incident_id=incident.incident_id,
            )

        except Exception as e:
            errors.append(f"{approval_id}: {str(e)}")
            logger.error(
                "incident_sync_error",
                approval_id=approval_id,
                error=str(e),
            )

    logger.info(
        "sync_from_approvals_completed",
        synced=synced,
        skipped=skipped,
        errors=len(errors),
    )

    return SyncResult(
        synced=synced,
        skipped=skipped,
        errors=errors,
        details=details,
    )
