#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：performance.py
模块描述：性能测试 API 路由
  - Phase 1: CRUD 占位（已完成）
  - Phase 3: 执行/停止/快照/报告/WebSocket

作者：czj
创建日期：2026-08-12
最后修改：2026-08-12
"""

import json
import logging
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSocketDisconnect
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from app.schemas.performance import (
    PerformanceTaskCreate,
    PerformanceTaskUpdate,
    PerformanceTaskResponse,
    PerformanceTaskListItem,
    PerformanceTaskListResponse,
    PerformanceRunRequest,
    PerformanceRunResponse,
    PerformanceSnapshotResponse,
    PerformanceSnapshotListResponse,
    PerformanceReportResponse,
    PerformanceReportSummary,
    PerformanceReportMetrics,
)
from app.services.performance_service import PerformanceService
from app.websocket.manager import manager

logger = logging.getLogger(__name__)

router = APIRouter()


# ==================== 依赖注入 ====================

async def get_perf_service(db: AsyncSession = Depends(get_db)) -> PerformanceService:
    """获取 PerformanceService 实例"""
    return PerformanceService(db)


# ==================== Phase 1: CRUD ====================


@router.get("/tasks", response_model=PerformanceTaskListResponse)
async def list_tasks(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(20, ge=1, le=100, description="每页数量"),
    status: Optional[str] = Query(None, description="按状态过滤"),
    service: PerformanceService = Depends(get_perf_service),
):
    """获取性能测试任务列表（分页）"""
    items, total = await service.list_tasks(page=page, page_size=page_size, status=status)
    return PerformanceTaskListResponse(
        total=total,
        items=[PerformanceTaskListItem(**t.to_dict()) for t in items],
    )


@router.post("/tasks", response_model=PerformanceTaskResponse, status_code=201)
async def create_task(
    data: PerformanceTaskCreate,
    service: PerformanceService = Depends(get_perf_service),
):
    """创建性能测试任务"""
    task = await service.create_task(data)
    return PerformanceTaskResponse(**task.to_dict())


@router.get("/tasks/{task_id}", response_model=PerformanceTaskResponse)
async def get_task(
    task_id: str,
    service: PerformanceService = Depends(get_perf_service),
):
    """获取性能测试任务详情"""
    task = await service.get_task(task_id)
    if not task:
        raise HTTPException(status_code=404, detail="任务不存在")
    return PerformanceTaskResponse(**task.to_dict())


@router.put("/tasks/{task_id}", response_model=PerformanceTaskResponse)
async def update_task(
    task_id: str,
    data: PerformanceTaskUpdate,
    service: PerformanceService = Depends(get_perf_service),
):
    """更新性能测试任务"""
    try:
        task = await service.update_task(task_id, data.model_dump(exclude_unset=True))
        if not task:
            raise HTTPException(status_code=404, detail="任务不存在")
        return PerformanceTaskResponse(**task.to_dict())
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.delete("/tasks/{task_id}", status_code=204)
async def delete_task(
    task_id: str,
    service: PerformanceService = Depends(get_perf_service),
):
    """删除性能测试任务"""
    try:
        deleted = await service.delete_task(task_id)
        if not deleted:
            raise HTTPException(status_code=404, detail="任务不存在")
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


# ==================== Phase 3: 执行/停止 ====================


@router.post("/tasks/{task_id}/run", response_model=PerformanceRunResponse)
async def run_task(
    task_id: str,
    data: PerformanceRunRequest = None,
    service: PerformanceService = Depends(get_perf_service),
):
    """
    执行性能测试任务

    在后台线程池中运行压测引擎，执行完成后自动更新任务结果。
    支持通过 config_override 临时覆盖配置项。
    """
    if data is None:
        data = PerformanceRunRequest()

    try:
        result = await service.run_task(
            task_id,
            config_override=data.config_override,
        )
        return PerformanceRunResponse(
            message="任务执行完成" if result.get("status") == "completed" else "任务执行失败",
            task_id=task_id,
            status=result.get("status", "failed"),
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.post("/tasks/{task_id}/stop", response_model=PerformanceRunResponse)
async def stop_task(
    task_id: str,
    service: PerformanceService = Depends(get_perf_service),
):
    """
    停止正在运行的性能测试任务

    发送停止信号给执行引擎，引擎在下次分片检查时退出。
    """
    stopped = await service.stop_task(task_id)
    if not stopped:
        # 检查任务是否存在
        task = await service.get_task(task_id)
        if not task:
            raise HTTPException(status_code=404, detail="任务不存在")
        # 存在但不在运行中，返回提示
        return PerformanceRunResponse(
            message="任务当前不在运行状态",
            task_id=task_id,
            status=task.status,
        )

    return PerformanceRunResponse(
        message="已发送停止信号",
        task_id=task_id,
        status="cancelled",
    )


# ==================== Phase 3: 快照/报告 ====================


@router.get("/tasks/{task_id}/snapshots", response_model=PerformanceSnapshotListResponse)
async def get_snapshots(
    task_id: str,
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(500, ge=1, le=5000, description="每页数量"),
    service: PerformanceService = Depends(get_perf_service),
):
    """获取性能测试快照数据（分页，按时间升序）"""
    snapshots, total = await service.get_snapshots(
        task_id, page=page, page_size=page_size
    )
    return PerformanceSnapshotListResponse(
        total=total,
        items=[PerformanceSnapshotResponse(**s.to_dict()) for s in snapshots],
    )


@router.get("/tasks/{task_id}/report", response_model=PerformanceReportResponse)
async def get_report(
    task_id: str,
    service: PerformanceService = Depends(get_perf_service),
):
    """
    获取性能测试报告

    返回完整报告数据，包含执行摘要、指标统计和所有快照。
    """
    report = await service.get_report(task_id)
    if not report:
        raise HTTPException(status_code=404, detail="任务不存在")

    return PerformanceReportResponse(
        summary=PerformanceReportSummary(**report["summary"]),
        metrics=PerformanceReportMetrics(**report["metrics"]),
        snapshots=[PerformanceSnapshotResponse(**s) for s in report["snapshots"]],
    )


@router.get("/tasks/{task_id}/results", response_model=PerformanceTaskResponse)
async def get_task_results(
    task_id: str,
    service: PerformanceService = Depends(get_perf_service),
):
    """获取性能测试任务执行结果详情"""
    task = await service.get_task(task_id)
    if not task:
        raise HTTPException(status_code=404, detail="任务不存在")
    return PerformanceTaskResponse(**task.to_dict())


# ==================== Phase 3: WebSocket 实时监控 ====================


@router.websocket("/ws/{task_id}")
async def websocket_monitor(websocket: WebSocket, task_id: str):
    """
    性能测试实时监控 WebSocket

    客户端连接后，每秒收到服务端推送的性能快照数据。
    消息格式:
    ```json
    {
        "type": "perf_snapshot",
        "task_id": "...",
        "data": {
            "elapsed": 5.0,
            "tps": 120.5,
            "avg_response_time": 45.2,
            "p50": 32.1,
            "p90": 89.4,
            "p99": 245.6,
            "success_count": 120,
            "fail_count": 0,
            "total_requests": 600,
            "status_2xx": 120,
            "status_4xx": 0,
            "status_5xx": 0
        },
        "timestamp": "2026-08-12T12:00:00"
    }
    ```
    执行完成时推送:
    ```json
    {
        "type": "perf_complete",
        "task_id": "...",
        "status": "completed",
        "data": { ... }
    }
    ```
    """
    ws_group = f"perf_{task_id}"
    await manager.connect(websocket, ws_group)

    try:
        # 保持连接，等待推送
        while True:
            # 接收客户端消息（可处理暂停/恢复等指令）
            try:
                data = await websocket.receive_text()
                # 可以处理客户端发送的指令，目前仅保持连接
                msg = json.loads(data)
                if msg.get("type") == "ping":
                    await manager.send_to(websocket, {"type": "pong"})
            except json.JSONDecodeError:
                pass
    except WebSocketDisconnect:
        logger.info(f"WebSocket 断开连接: task_id={task_id}")
    except Exception as e:
        logger.error(f"WebSocket 异常: {e}")
    finally:
        await manager.disconnect(websocket, ws_group)