#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：performance.py
模块描述：性能测试 Pydantic 模式定义

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

from datetime import datetime
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field, ConfigDict


def to_camel(string: str) -> str:
    """Convert snake_case to camelCase"""
    components = string.split('_')
    return components[0] + ''.join(
        # 数字开头的组件不做 title-case（避免 "2xx" → "2Xx"）
        x if x[0].isdigit() else x.title()
        for x in components[1:]
    )


# ==================== 断言规则 ====================

class AssertionRule(BaseModel):
    """断言规则"""
    type: str = Field(..., description="断言类型: status_code/response_time/response_body")
    operator: str = Field(..., description="运算符: equals/not_equals/less_than/greater_than/json_path")
    value: Any = Field(..., description="期望值")
    path: Optional[str] = Field(None, description="JSON Path (response_body 类型时使用)")
    description: str = Field("", description="断言描述")


# ==================== 性能测试任务 ====================

class PerformanceTaskCreate(BaseModel):
    """创建性能测试任务"""
    name: str = Field(..., min_length=1, max_length=200, description="任务名称")
    description: str = Field("", description="任务描述")

    # 目标配置
    target_url: str = Field(..., description="目标接口完整URL")
    method: str = Field("GET", description="HTTP方法 (GET/POST/PUT/DELETE)")
    headers: Dict[str, str] = Field(default_factory=dict, description="自定义请求头")
    body: Optional[Dict[str, Any]] = Field(None, description="请求体")
    body_template: Optional[Dict[str, Any]] = Field(None, description="请求体模板")

    # 压测配置
    mode: str = Field("concurrent", description="压测模式: concurrent/qps/step")
    concurrency: int = Field(10, ge=1, le=500, description="并发数")
    qps_target: int = Field(100, ge=1, description="目标QPS")
    duration: int = Field(60, ge=1, le=3600, description="压测时长(秒)")
    ramp_up: int = Field(10, ge=0, description="预热时间(秒)")
    step_concurrency: List[int] = Field(default_factory=list, description="阶梯并发配置")
    step_duration: int = Field(60, ge=1, description="每阶梯时长(秒)")

    # 认证配置
    auth_required: bool = Field(True, description="是否需要登录Token")
    account_key: str = Field("superadmin", description="使用的账号")

    # 断言配置
    assertions: List[AssertionRule] = Field(default_factory=list, description="断言规则列表")

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceTaskUpdate(BaseModel):
    """更新性能测试任务（所有字段可选）"""
    name: Optional[str] = Field(None, min_length=1, max_length=200, description="任务名称")
    description: Optional[str] = Field(None, description="任务描述")
    target_url: Optional[str] = Field(None, description="目标接口完整URL")
    method: Optional[str] = Field(None, description="HTTP方法")
    headers: Optional[Dict[str, str]] = Field(None, description="自定义请求头")
    body: Optional[Dict[str, Any]] = Field(None, description="请求体")
    body_template: Optional[Dict[str, Any]] = Field(None, description="请求体模板")
    mode: Optional[str] = Field(None, description="压测模式")
    concurrency: Optional[int] = Field(None, ge=1, le=500, description="并发数")
    qps_target: Optional[int] = Field(None, ge=1, description="目标QPS")
    duration: Optional[int] = Field(None, ge=1, le=3600, description="压测时长(秒)")
    ramp_up: Optional[int] = Field(None, ge=0, description="预热时间(秒)")
    step_concurrency: Optional[List[int]] = Field(None, description="阶梯并发配置")
    step_duration: Optional[int] = Field(None, ge=1, description="每阶梯时长(秒)")
    auth_required: Optional[bool] = Field(None, description="是否需要登录Token")
    account_key: Optional[str] = Field(None, description="使用的账号")
    assertions: Optional[List[AssertionRule]] = Field(None, description="断言规则列表")

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceTaskResponse(BaseModel):
    """性能测试任务响应"""
    id: str
    name: str
    description: str = ""
    status: str = "pending"
    error_message: Optional[str] = None
    target_url: str = ""
    method: str = "GET"
    headers: Dict[str, str] = {}
    body: Optional[Dict[str, Any]] = None
    body_template: Optional[Dict[str, Any]] = None
    mode: str = "concurrent"
    concurrency: int = 10
    qps_target: int = 100
    duration: int = 60
    ramp_up: int = 10
    step_concurrency: List[int] = []
    step_duration: int = 60
    auth_required: bool = True
    account_key: str = "superadmin"
    assertions: List[Dict[str, Any]] = []

    # 结果统计
    total_requests: int = 0
    success_count: int = 0
    fail_count: int = 0
    min_response_time: float = 0.0
    max_response_time: float = 0.0
    avg_response_time: float = 0.0
    p50_response_time: float = 0.0
    p90_response_time: float = 0.0
    p99_response_time: float = 0.0
    actual_tps: float = 0.0
    error_rate: float = 0.0

    # 时间
    start_time: Optional[str] = None
    end_time: Optional[str] = None
    duration_actual: float = 0.0
    created_at: Optional[str] = None
    updated_at: Optional[str] = None

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceTaskListItem(BaseModel):
    """性能测试任务列表项（简洁版）"""
    id: str
    name: str
    status: str
    mode: str
    target_url: str
    total_requests: int = 0
    actual_tps: float = 0.0
    avg_response_time: float = 0.0
    error_rate: float = 0.0
    duration_actual: float = 0.0
    start_time: Optional[str] = None
    end_time: Optional[str] = None
    created_at: Optional[str] = None

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


# ==================== 执行请求/响应 ====================

class PerformanceRunRequest(BaseModel):
    """执行性能测试任务请求"""
    config_override: Optional[Dict[str, Any]] = Field(None, description="可覆盖的配置项")

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceRunResponse(BaseModel):
    """执行性能测试任务响应"""
    message: str
    task_id: str
    status: str

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


# ==================== 快照 ====================

class PerformanceSnapshotResponse(BaseModel):
    """性能测试快照响应"""
    id: int
    task_id: str
    timestamp: float
    elapsed: float
    concurrent_users: int = 0
    tps: float = 0.0
    avg_response_time: float = 0.0
    min_response_time: float = 0.0
    max_response_time: float = 0.0
    p50_response_time: float = 0.0
    p90_response_time: float = 0.0
    p99_response_time: float = 0.0
    success_count: int = 0
    fail_count: int = 0
    status_2xx: int = Field(0, alias="status2xx")
    status_3xx: int = Field(0, alias="status3xx")
    status_4xx: int = Field(0, alias="status4xx")
    status_5xx: int = Field(0, alias="status5xx")

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


# ==================== 报告 ====================

class PerformanceReportSummary(BaseModel):
    """性能测试报告摘要"""
    task_id: str
    task_name: str
    target_url: str
    method: str
    mode: str
    concurrency: int = 0
    duration_setting: int = 0
    duration_actual: float = 0.0
    start_time: Optional[str] = None
    end_time: Optional[str] = None
    account_key: str = ""

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceReportMetrics(BaseModel):
    """性能测试报告指标"""
    total_requests: int = 0
    success_count: int = 0
    fail_count: int = 0
    error_rate: float = 0.0
    actual_tps: float = 0.0
    min_response_time: float = 0.0
    max_response_time: float = 0.0
    avg_response_time: float = 0.0
    p50_response_time: float = 0.0
    p90_response_time: float = 0.0
    p99_response_time: float = 0.0
    status_2xx: int = Field(0, alias="status2xx")
    status_3xx: int = Field(0, alias="status3xx")
    status_4xx: int = Field(0, alias="status4xx")
    status_5xx: int = Field(0, alias="status5xx")

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceReportResponse(BaseModel):
    """性能测试报告完整响应"""
    summary: PerformanceReportSummary
    metrics: PerformanceReportMetrics
    snapshots: List[PerformanceSnapshotResponse] = []

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


# ==================== 列表 ====================

class PerformanceTaskListResponse(BaseModel):
    """性能测试任务列表响应"""
    total: int
    items: List[PerformanceTaskListItem]

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


class PerformanceSnapshotListResponse(BaseModel):
    """性能测试快照列表响应"""
    total: int
    items: List[PerformanceSnapshotResponse]

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)