# =============================================================================
# AWOOOI Statistics API - Phase 17 P1 分層修復
# =============================================================================
# 統計分析 API - 從 Episodic Memory 萃取洞察
#
# 核心價值:
# - 識別常見問題模式
# - 評估 AI 建議效能
# - 支援 Playbook 萃取
#
# 架構變更 (2026-03-28):
# - Router 層不再直接存取 DB
# - 所有查詢邏輯已移至 StatsService
# - 符合 leWOOOgo 分層規範
#
# @author Claude Code (首席架構師)
# @version 2.0.0
# @date 2026-03-28 (台北時間)
# @see feedback_lewooogo_modular_enforcement.md
# =============================================================================

import asyncio
import json
from typing import Annotated, Any

from fastapi import APIRouter, Depends, Query, WebSocket, WebSocketDisconnect
from fastapi.responses import PlainTextResponse
from pydantic import BaseModel, Field

from src.services.stats_service import StatsService, get_stats_service
from src.services.k3s_monitor_service import K3sMonitorService, get_k3s_monitor_service
from src.services.weekly_report_service import WeeklyReportService, get_weekly_report_service
from src.services.flywheel_stats_service import FlywheelStatsService, get_flywheel_stats_service

router = APIRouter(prefix="/stats", tags=["Statistics"])


# =============================================================================
# Dependencies
# =============================================================================

StatsServiceDep = Annotated[StatsService, Depends(get_stats_service)]
K3sMonitorDep = Annotated[K3sMonitorService, Depends(get_k3s_monitor_service)]
WeeklyReportDep = Annotated[WeeklyReportService, Depends(get_weekly_report_service)]


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


class StatusCount(BaseModel):
    """狀態計數"""

    status: str
    count: int


class SeverityCount(BaseModel):
    """嚴重度計數"""

    severity: str
    count: int


class IncidentSummary(BaseModel):
    """事件總覽"""

    total_incidents: int = Field(description="總事件數")
    status_distribution: list[StatusCount] = Field(description="狀態分佈")
    severity_distribution: list[SeverityCount] = Field(description="嚴重度分佈")
    resolved_rate: float = Field(description="解決率 (%)")
    avg_signals_per_incident: float = Field(description="平均告警聚合數")


class ResolutionStats(BaseModel):
    """解決時間統計"""

    avg_minutes: float | None = Field(description="平均解決時間 (分鐘)")
    p50_minutes: float | None = Field(description="P50 解決時間")
    p95_minutes: float | None = Field(description="P95 解決時間")
    fastest_minutes: float | None = Field(description="最快解決時間")
    slowest_minutes: float | None = Field(description="最慢解決時間")
    sample_size: int = Field(description="樣本數")


class TrendPoint(BaseModel):
    """趨勢數據點"""

    date: str
    count: int


class IncidentTrends(BaseModel):
    """事件趨勢"""

    period: str = Field(description="週期 (daily/weekly/monthly)")
    data: list[TrendPoint]


class AIPerformance(BaseModel):
    """AI 效能統計"""

    total_proposals: int = Field(description="總提案數")
    executed_count: int = Field(description="已執行數")
    execution_rate: float = Field(description="執行率 (%)")
    success_count: int = Field(description="成功數")
    success_rate: float = Field(description="成功率 (%)")
    avg_effectiveness: float | None = Field(description="平均有效性評分 (1-5)")
    effectiveness_distribution: dict[int, int] = Field(
        description="有效性評分分佈 {1: count, 2: count, ...}"
    )


class ServiceImpact(BaseModel):
    """服務影響統計"""

    service: str
    incident_count: int
    severity_breakdown: dict[str, int] = Field(description="{P0: 5, P1: 10, ...}")


class FeedbackSummary(BaseModel):
    """人類回饋摘要"""

    total_feedback: int
    positive_count: int = Field(description="正面回饋 (score >= 4)")
    neutral_count: int = Field(description="中性回饋 (score == 3)")
    negative_count: int = Field(description="負面回饋 (score <= 2)")
    common_themes: list[str] = Field(description="常見主題 (從 learning_notes 萃取)")


# =============================================================================
# API Endpoints (Phase 17 P1: 薄轉發層)
# =============================================================================


@router.get(
    "/incidents/summary",
    response_model=IncidentSummary,
    summary="事件總覽統計",
)
async def get_incident_summary(
    days: int = Query(30, ge=1, le=365, description="統計區間 (天)"),
    service: StatsServiceDep = None,
) -> IncidentSummary:
    """
    取得事件總覽統計

    包含:
    - 總事件數
    - 狀態分佈
    - 嚴重度分佈
    - 解決率
    """
    result = await service.get_incident_summary(days)
    return IncidentSummary(
        total_incidents=result["total_incidents"],
        status_distribution=[
            StatusCount(**s) for s in result["status_distribution"]
        ],
        severity_distribution=[
            SeverityCount(**s) for s in result["severity_distribution"]
        ],
        resolved_rate=result["resolved_rate"],
        avg_signals_per_incident=result["avg_signals_per_incident"],
    )


@router.get(
    "/incidents/resolution",
    response_model=ResolutionStats,
    summary="解決時間統計",
)
async def get_resolution_stats(
    days: int = Query(30, ge=1, le=365, description="統計區間 (天)"),
    service: StatsServiceDep = None,
) -> ResolutionStats:
    """
    取得解決時間統計

    計算已解決事件的:
    - 平均解決時間
    - P50/P95 解決時間
    - 最快/最慢解決時間
    """
    result = await service.get_resolution_stats(days)
    return ResolutionStats(**result)


@router.get(
    "/ai-performance",
    response_model=AIPerformance,
    summary="AI 效能統計",
)
async def get_ai_performance(
    days: int = Query(30, ge=1, le=365, description="統計區間 (天)"),
    service: StatsServiceDep = None,
) -> AIPerformance:
    """
    取得 AI 提案效能統計

    評估指標:
    - 提案執行率
    - 執行成功率
    - 有效性評分分佈
    """
    result = await service.get_ai_performance(days)
    return AIPerformance(**result)


@router.get(
    "/services/affected",
    response_model=list[ServiceImpact],
    summary="受影響服務排名",
)
async def get_affected_services(
    days: int = Query(30, ge=1, le=365, description="統計區間 (天)"),
    limit: int = Query(10, ge=1, le=50, description="返回數量"),
    service: StatsServiceDep = None,
) -> list[ServiceImpact]:
    """
    取得最常受影響的服務排名

    包含:
    - 事件計數
    - 嚴重度分佈
    """
    results = await service.get_affected_services(days, limit)
    return [ServiceImpact(**r) for r in results]


@router.get(
    "/incidents/trends",
    response_model=IncidentTrends,
    summary="事件趨勢分析",
)
async def get_incident_trends(
    days: int = Query(30, ge=7, le=365, description="統計區間 (天)"),
    period: str = Query("daily", description="週期: daily/weekly/monthly"),
    service: StatsServiceDep = None,
) -> IncidentTrends:
    """
    取得事件趨勢數據

    支援週期:
    - daily: 每日事件數
    - weekly: 每週事件數
    - monthly: 每月事件數
    """
    result = await service.get_incident_trends(days, period)
    return IncidentTrends(
        period=result["period"],
        data=[TrendPoint(**p) for p in result["data"]],
    )


@router.get(
    "/feedback/summary",
    response_model=FeedbackSummary,
    summary="人類回饋摘要",
)
async def get_feedback_summary(
    days: int = Query(30, ge=1, le=365, description="統計區間 (天)"),
    service: StatsServiceDep = None,
) -> FeedbackSummary:
    """
    取得人類回饋統計

    從 Incident outcome 中萃取:
    - 正面/中性/負面回饋比例
    - 常見主題 (從 learning_notes 萃取)
    """
    result = await service.get_feedback_summary(days)
    return FeedbackSummary(**result)


# =============================================================================
# K3s Status Report (Phase 21.2)
# =============================================================================


class K3sStatusResponse(BaseModel):
    """K3s 叢集狀態回應"""

    report_date: str = Field(description="報告日期時間")
    node_total: int = Field(description="節點總數")
    node_ready: int = Field(description="就緒節點數")
    pod_running: int = Field(description="執行中 Pod 數")
    pod_pending: int = Field(description="等待中 Pod 數")
    pod_failed: int = Field(description="失敗 Pod 數")
    hpa_api: str = Field(description="API HPA 副本數")
    hpa_web: str = Field(description="Web HPA 副本數")
    hpa_worker: str = Field(description="Worker HPA 副本數")
    alert_count_48h: int = Field(description="48h 內告警數")
    pod_restart_48h: int = Field(description="48h 內 Pod 重啟數")


@router.get(
    "/k3s/status",
    response_model=K3sStatusResponse,
    summary="K3s 叢集狀態",
)
async def get_k3s_status(
    monitor: K3sMonitorDep = None,
) -> K3sStatusResponse:
    """
    取得 K3s 叢集當前狀態

    數據來源: Prometheus (kube-state-metrics)
    """
    status = await monitor.collect_cluster_status()
    return K3sStatusResponse(
        report_date=status.report_date,
        node_total=status.node_total,
        node_ready=status.node_ready,
        pod_running=status.pod_running,
        pod_pending=status.pod_pending,
        pod_failed=status.pod_failed,
        hpa_api=status.hpa_api_replicas,
        hpa_web=status.hpa_web_replicas,
        hpa_worker=status.hpa_worker_replicas,
        alert_count_48h=status.alert_count_48h,
        pod_restart_48h=status.pod_restart_48h,
    )


@router.post(
    "/k3s/report",
    summary="觸發 K3s 報告",
)
async def trigger_k3s_report(
    monitor: K3sMonitorDep = None,
) -> dict:
    """
    手動觸發 K3s 狀態報告發送到 Telegram

    Phase 21.2: 定期報告機制
    """
    success = await monitor.send_daily_report()
    return {
        "success": success,
        "message": "報告已發送" if success else "報告發送失敗",
    }


# =============================================================================
# Weekly Report (Phase 21.3)
# =============================================================================


class WeeklyReportResponse(BaseModel):
    """週報回應"""

    week_range: str = Field(description="週次 (e.g., 2026-W14)")
    report_date: str = Field(description="報告日期時間")
    alert_total: int = Field(description="本週告警總數")
    resolved_rate: float = Field(description="解決率 (%)")
    ai_proposal_count: int = Field(description="AI 提案數")
    ai_success_rate: float = Field(description="AI 成功率 (%)")
    commits_count: int = Field(description="本週 Commits 數")
    deploy_count: int = Field(description="本週部署次數")


@router.get(
    "/weekly/preview",
    response_model=WeeklyReportResponse,
    summary="預覽週報",
)
async def preview_weekly_report(
    service: WeeklyReportDep = None,
) -> WeeklyReportResponse:
    """
    預覽本週週報內容 (不發送)

    Phase 21.3: 定期報告機制
    """
    report = await service.generate_report()
    return WeeklyReportResponse(
        week_range=report.week_range,
        report_date=report.report_date,
        alert_total=report.alert_total,
        resolved_rate=report.resolved_rate,
        ai_proposal_count=report.ai_proposal_count,
        ai_success_rate=report.ai_success_rate,
        commits_count=report.commits_count,
        deploy_count=report.deploy_count,
    )


@router.post(
    "/weekly/report",
    summary="觸發週報",
)
async def trigger_weekly_report(
    service: WeeklyReportDep = None,
) -> dict:
    """
    手動觸發週報發送到 Telegram

    Phase 21.3: 定期報告機制
    """
    success = await service.send_weekly_report()
    return {
        "success": success,
        "message": "週報已發送" if success else "週報發送失敗",
    }


# =============================================================================
# 2026-04-07 Claude Code: Sprint 4 C1 — 告警處置統計
# =============================================================================


class DispositionSummary(BaseModel):
    """處置類型分佈"""
    total: int = Field(default=0, description="總處置次數")
    auto_repair: int = Field(default=0, description="自動修復次數")
    human_approved: int = Field(default=0, description="人工審核批准次數")
    manual_resolved: int = Field(default=0, description="手動處理次數")
    cold_start_trust: int = Field(default=0, description="冷啟動信任次數")
    auto_rate: float = Field(default=0.0, description="自動化率 (auto_repair + cold_start) / total")
    human_rate: float = Field(default=0.0, description="人工介入率")


class DispositionByAnomaly(BaseModel):
    """按異常類型的處置分佈"""
    anomaly_key: str
    alert_name: str = ""
    disposition: DispositionSummary


class DispositionResponse(BaseModel):
    """處置統計 API 回應"""
    summary: DispositionSummary
    by_anomaly: list[DispositionByAnomaly] = Field(default_factory=list)


@router.get(
    "/disposition",
    response_model=DispositionResponse,
    summary="告警處置統計",
)
async def get_disposition_stats() -> DispositionResponse:
    """
    取得告警處置類型分佈統計。
    2026-04-07 Claude Code: Sprint 4 C1
    2026-04-07 Claude Code: P0-2 Fix — 封裝到 Service 層，Router 不直接存取 Redis

    包含:
    - 總覽: 自動修復/人工審核/手動處理/冷啟動信任 各幾次
    - 自動化率
    - 按異常類型明細
    """
    try:
        from src.services.anomaly_counter import get_anomaly_counter
        counter = get_anomaly_counter()

        # P0-2 Fix: 呼叫 Service 層封裝方法，不直接存取 Redis
        total_summary, by_anomaly_raw = await counter.get_all_disposition_stats()

        by_anomaly: list[DispositionByAnomaly] = []
        for item in by_anomaly_raw:
            d_total = item["total"]
            auto_cnt = item["auto_repair"] + item["cold_start_trust"]
            by_anomaly.append(DispositionByAnomaly(
                anomaly_key=item["anomaly_key"],
                alert_name=item.get("alert_name", ""),
                disposition=DispositionSummary(
                    total=d_total,
                    auto_repair=item["auto_repair"],
                    human_approved=item["human_approved"],
                    manual_resolved=item["manual_resolved"],
                    cold_start_trust=item["cold_start_trust"],
                    auto_rate=auto_cnt / d_total if d_total > 0 else 0,
                    human_rate=item["human_approved"] / d_total if d_total > 0 else 0,
                ),
            ))

        total = total_summary["total"]
        auto_cnt = total_summary["auto_repair"] + total_summary["cold_start_trust"]

        return DispositionResponse(
            summary=DispositionSummary(
                **total_summary,
                auto_rate=auto_cnt / total if total > 0 else 0,
                human_rate=total_summary["human_approved"] / total if total > 0 else 0,
            ),
            by_anomaly=by_anomaly,
        )

    except Exception as e:
        import structlog
        structlog.get_logger(__name__).warning("disposition_stats_error", error=str(e))
        return DispositionResponse(summary=DispositionSummary())


# =============================================================================
# ADR-073-C C1 + ADR-074 M1 — 飛輪健康度 API
# 2026-04-12 ogt
# =============================================================================

FlywheelStatsDep = Annotated[FlywheelStatsService, Depends(get_flywheel_stats_service)]


@router.get(
    "/flywheel",
    summary="飛輪六節點即時狀態（ADR-073-C C1）",
    response_model=None,
)
async def get_flywheel_stats(svc: FlywheelStatsDep) -> dict[str, Any]:
    """
    飛輪六節點即時狀態 + 當前流動中的告警。
    供前端飛輪動畫元件接真實數據。
    """
    metrics = await svc.compute()
    return metrics.to_flywheel_api_dict()


@router.get(
    "/summary",
    summary="飛輪 KPI 摘要（ADR-073-C C1）",
    response_model=None,
)
async def get_flywheel_summary(svc: FlywheelStatsDep) -> dict[str, Any]:
    """
    飛輪 KPI 面板數據：Playbook 數、成功率、今日處理數、KM 向量化率。
    供前端右上角三個 KPI 卡片顯示真實數據。
    """
    metrics = await svc.compute()
    return metrics.to_summary_api_dict()


@router.get(
    "/flywheel/metrics",
    summary="Prometheus 飛輪健康度指標（ADR-074 M1）",
    response_class=PlainTextResponse,
)
async def get_flywheel_prometheus_metrics(svc: FlywheelStatsDep) -> PlainTextResponse:
    """
    Prometheus text format 飛輪健康度指標。
    Prometheus scrape target: /api/v1/stats/flywheel/metrics

    Metrics:
      awoooi_flywheel_playbook_count
      awoooi_flywheel_execution_success_rate
      awoooi_flywheel_km_unvectorized_count
      awoooi_flywheel_alertname_null_rate
      awoooi_flywheel_incidents_stuck
      awoooi_flywheel_km_vectorized_rate
    """
    metrics = await svc.compute()
    return PlainTextResponse(
        content=metrics.to_prometheus_lines(),
        media_type="text/plain; version=0.0.4; charset=utf-8",
    )


# =============================================================================
# ADR-073-C C3: WebSocket 即時飛輪推送
# =============================================================================

@router.websocket("/flywheel/ws")
async def flywheel_websocket(websocket: WebSocket) -> None:
    """
    WebSocket 即時飛輪健康度推送 — ADR-073-C C3

    每 10 秒推送一次 FlywheelSummary JSON。
    前端連線路徑：ws(s)://<host>/api/v1/stats/flywheel/ws

    Protocol:
      Server → Client: {"type": "flywheel_summary", "data": {...}, "ts": "ISO8601"}
      Client → Server: (ignored)
    """
    svc = get_flywheel_stats_service()
    await websocket.accept()
    try:
        while True:
            metrics = await svc.compute()
            payload = json.dumps({
                "type": "flywheel_summary",
                "data": metrics.to_summary_api_dict(),
                "ts": metrics.computed_at.isoformat(),
            })
            await websocket.send_text(payload)
            await asyncio.sleep(10)
    except WebSocketDisconnect:
        pass
