#!/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

from app.schemas.performance_output import CaptureRule


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 TransactionStep(BaseModel):
    """事务步骤配置"""
    name: str = Field(..., description="步骤名称（用于报告展示）")
    url: str = Field(..., description="步骤目标URL")
    method: str = Field("GET", description="HTTP方法")
    headers: Dict[str, str] = Field(default_factory=dict, description="步骤级请求头")
    body: Optional[Any] = Field(None, description="步骤请求体")
    body_template: Optional[Any] = Field(None, description="步骤请求体模板")
    assertions: List[AssertionRule] = Field(default_factory=list, description="步骤级断言规则")
    capture_rules: Optional[List[Dict[str, Any]]] = Field(None, description="步骤级响应捕获规则")
    timeout: int = Field(30, ge=1, le=120, description="步骤超时(秒)")

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


class TransactionStepResult(BaseModel):
    """事务步骤执行结果"""
    step_name: str = Field("", description="步骤名称")
    step_index: int = Field(0, description="步骤序号")
    status: int = Field(0, description="HTTP状态码（0=网络异常）")
    success: bool = Field(True, description="是否成功")
    elapsed_ms: float = Field(0.0, description="步骤耗时(ms)")
    latency_ms: float = Field(0.0, description="首字节延迟(ms)")
    connect_ms: float = Field(0.0, description="连接时间(ms)")
    sent_bytes: int = Field(0, description="发送字节数")
    received_bytes: int = Field(0, description="接收字节数")
    error_message: str = Field("", description="错误信息")
    captured: Dict[str, Any] = Field(default_factory=dict, description="该步骤捕获的响应字段")

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


# ==================== 唯一性字段规则 ====================

class UniqueFieldRule(BaseModel):
    """唯一性字段规则"""
    field: str = Field(..., description="JSON Path 定位字段，如 'templateName' 或 `topicList[0].topicName`")
    strategy: str = Field(default="suffix", pattern=r"^(suffix|template)$", description="唯一化策略: suffix/template")
    template: Optional[str] = Field(default=None, description="strategy=template 时使用的模板，如 '{__UUID__}'")

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


# ==================== 场景增强 ====================

class ScenarioApiConfig(BaseModel):
    """长稳压测（endurance）多接口配置"""
    name: str = Field(..., description="接口名称（用于报告展示）")
    method: str = Field("GET", description="HTTP方法")
    url: str = Field(..., description="接口目标URL")
    headers: Dict[str, str] = Field(default_factory=dict, description="接口级请求头")
    body: Optional[Any] = Field(None, description="请求体")
    thread_count: int = Field(1, ge=1, le=1000, description="该接口分配的线程数")
    assertions: List[AssertionRule] = Field(default_factory=list, description="接口级断言规则")
    unique_fields: Optional[List[UniqueFieldRule]] = Field(default=None, description="接口级唯一性字段配置")

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


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

class PerformanceTaskCreate(BaseModel):
    """创建性能测试任务"""
    name: str = Field(..., min_length=1, max_length=200, description="任务名称")
    description: Optional[str] = Field(None, description="任务描述, 留空使用空串")
    project_id: Optional[str] = Field(None, description="归属项目ID")

    # 目标配置
    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[Any] = Field(None, description="请求体（支持 dict 或 list）")
    body_template: Optional[Any] = Field(None, description="请求体模板")

    # 压测配置
    mode: str = Field("concurrent", description="压测模式: concurrent/qps/step")
    concurrency: int = Field(10, ge=1, le=1000, description="并发数")
    qps_target: Optional[int] = Field(default=None, ge=1, description="目标QPS（留空使用默认值100）")
    duration: int = Field(60, ge=1, le=28800, description="压测时长(秒)")
    ramp_up: Optional[int] = Field(default=None, ge=0, description="预热时间(秒)（留空使用默认值10）")
    step_concurrency: Optional[List[int]] = Field(default=None, description="阶梯并发配置（留空使用默认值[]）")
    step_duration: Optional[int] = Field(default=None, ge=1, description="每阶梯时长(秒)（留空使用默认值60）")

    # 场景增强（瞬时并发/长稳压测）
    scenario_type: Optional[str] = Field(None, description="场景类型: burst/endurance（null=标准模式）")
    scenario_apis: Optional[List[ScenarioApiConfig]] = Field(None, description="长稳接口列表，每接口独立线程数")
    loop_type: str = Field("finite", description="循环类型: finite(有限次)/infinite(无限)")
    loop_count: int = Field(1, ge=1, le=100000, description="有限循环次数")
    synchronizing_timer_enabled: bool = Field(False, description="是否启用集合点")
    synchronizing_timer_count: int = Field(0, ge=0, le=1000, description="集合点阈值")
    synchronizing_timer_timeout: int = Field(30000, ge=1000, le=120000, description="集合点等待超时(ms)")
    error_action: str = Field("continue", pattern=r"^(continue|stop)$", description="错误动作: continue/stop")
    think_time_enabled: bool = Field(False, description="是否启用思考时间")
    think_time_min: int = Field(1000, ge=0, le=60000, description="均值/固定思考时间(ms)")
    think_time_max: int = Field(3000, ge=0, le=60000, description="高斯分布偏差上限(ms)")
    think_time_distribution: str = Field("constant", pattern=r"^(constant|gaussian)$", description="分布类型: constant/gaussian")
    csv_parameterization_enabled: bool = Field(False, description="是否启用CSV参数化")
    csv_content: str = Field("", max_length=10000, description="CSV文件内容（首行表头）")
    csv_variable_mapping: Dict[str, str] = Field(default_factory=dict, description="CSV列名→变量名映射")

    # 认证配置
    auth_required: bool = Field(True, description="是否需要登录Token")
    account_key: str = Field("superadmin", description="使用的账号")
    login_username: Optional[str] = Field(None, description="自定义登录用户名，留空使用默认")
    login_password: Optional[str] = Field(None, description="自定义登录密码，留空使用默认")

    # 签名配置
    sign_request: bool = Field(False, description="请求是否需要签名(X-RANDOM/X-TIMESTAMP/X-SIGN)")

    # 关联接口预设
    preset_id: Optional[str] = Field(None, description="关联的接口预设ID")

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

    # 响应捕获规则
    capture_rules: Optional[List[CaptureRule]] = Field(None, description="响应捕获规则列表")

    # 唯一性字段配置
    unique_fields: Optional[List[UniqueFieldRule]] = Field(default=None, alias="uniqueFields", description="唯一性字段配置列表")

    # 事务配置（多步骤事务模式，steps 为空/None 则按单接口模式执行）
    steps: Optional[List[TransactionStep]] = Field(None, description="事务步骤列表")
    transaction_fail_policy: str = Field("fail_fast", pattern=r"^(fail_fast|continue)$", description="事务失败策略: fail_fast/continue")
    transaction_timeout: int = Field(60, ge=1, le=120, 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="任务描述")
    project_id: Optional[str] = Field(None, description="归属项目ID")
    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[Any] = Field(None, description="请求体（支持 dict 或 list）")
    body_template: Optional[Any] = Field(None, description="请求体模板")
    mode: Optional[str] = Field(None, description="压测模式")
    concurrency: Optional[int] = Field(None, ge=1, le=1000, description="并发数")
    qps_target: Optional[int] = Field(None, ge=1, description="目标QPS")
    duration: Optional[int] = Field(None, ge=1, le=28800, 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="每阶梯时长(秒)")

    # 场景增强（瞬时并发/长稳压测）
    scenario_type: Optional[str] = Field(None, description="场景类型: burst/endurance（null=标准模式）")
    scenario_apis: Optional[List[ScenarioApiConfig]] = Field(None, description="长稳接口列表，每接口独立线程数")
    loop_type: Optional[str] = Field(None, description="循环类型: finite/infinite")
    loop_count: Optional[int] = Field(None, ge=1, le=100000, description="有限循环次数")
    synchronizing_timer_enabled: Optional[bool] = Field(None, description="是否启用集合点")
    synchronizing_timer_count: Optional[int] = Field(None, ge=0, le=1000, description="集合点阈值")
    synchronizing_timer_timeout: Optional[int] = Field(None, ge=1000, le=120000, description="集合点等待超时(ms)")
    error_action: Optional[str] = Field(None, pattern=r"^(continue|stop)$", description="错误动作: continue/stop")
    think_time_enabled: Optional[bool] = Field(None, description="是否启用思考时间")
    think_time_min: Optional[int] = Field(None, ge=0, le=60000, description="均值/固定思考时间(ms)")
    think_time_max: Optional[int] = Field(None, ge=0, le=60000, description="高斯分布偏差上限(ms)")
    think_time_distribution: Optional[str] = Field(None, pattern=r"^(constant|gaussian)$", description="分布类型: constant/gaussian")
    csv_parameterization_enabled: Optional[bool] = Field(None, description="是否启用CSV参数化")
    csv_content: Optional[str] = Field(None, max_length=10000, description="CSV文件内容（首行表头）")
    csv_variable_mapping: Optional[Dict[str, str]] = Field(None, description="CSV列名→变量名映射")
    auth_required: Optional[bool] = Field(None, description="是否需要登录Token")
    account_key: Optional[str] = Field(None, description="使用的账号")
    login_username: Optional[str] = Field(None, description="自定义登录用户名，留空使用默认")
    login_password: Optional[str] = Field(None, description="自定义登录密码，留空使用默认")
    sign_request: Optional[bool] = Field(None, description="请求是否需要签名(X-RANDOM/X-TIMESTAMP/X-SIGN)")
    preset_id: Optional[str] = Field(None, description="关联的接口预设ID")
    assertions: Optional[List[AssertionRule]] = Field(None, description="断言规则列表")
    capture_rules: Optional[List[CaptureRule]] = Field(None, description="响应捕获规则列表")

    # 唯一性字段配置
    unique_fields: Optional[List[UniqueFieldRule]] = Field(default=None, alias="uniqueFields", description="唯一性字段配置列表")

    # 事务配置
    steps: Optional[List[TransactionStep]] = Field(None, description="事务步骤列表")
    transaction_fail_policy: Optional[str] = Field(None, pattern=r"^(fail_fast|continue)$", description="事务失败策略")
    transaction_timeout: Optional[int] = Field(None, ge=1, le=120, 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
    project_id: Optional[str] = None
    target_url: str = ""
    method: str = "GET"
    headers: Dict[str, str] = {}
    body: Optional[Any] = None
    body_template: Optional[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"
    login_username: Optional[str] = None
    login_password: Optional[str] = None
    sign_request: bool = False
    assertions: List[Dict[str, Any]] = []
    capture_rules: Optional[List[Dict[str, Any]]] = None
    preset_id: Optional[str] = None

    # 唯一性字段配置
    unique_fields: Optional[List[Dict[str, Any]]] = None

    # 事务配置
    steps: Optional[List[Dict[str, Any]]] = None
    transaction_fail_policy: str = "fail_fast"
    transaction_timeout: int = 60

    # 场景增强（瞬时并发/长稳压测）
    scenario_type: Optional[str] = None
    scenario_apis: Optional[List[Dict[str, Any]]] = None
    loop_type: str = "finite"
    loop_count: int = 1
    synchronizing_timer_enabled: bool = False
    synchronizing_timer_count: int = 0
    synchronizing_timer_timeout: int = 30000
    error_action: str = "continue"
    think_time_enabled: bool = False
    think_time_min: int = 1000
    think_time_max: int = 3000
    think_time_distribution: str = "constant"
    csv_parameterization_enabled: bool = False
    csv_content: Optional[str] = None
    csv_variable_mapping: Optional[Dict[str, str]] = None

    # 资源监控汇总
    resource_summary: Optional[Dict[str, Any]] = None
    # 目标机资源监控汇总
    target_resource_summary: Optional[Dict[str, Any]] = None
    # 事务处理汇总
    transaction_summary: Optional[Dict[str, Any]] = None
    # 接口维度指标汇总
    api_summary: Optional[List[Dict[str, Any]]] = None

    # 结果统计
    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
    p95_response_time: float = 0.0
    p99_response_time: float = 0.0
    std_dev: float = 0.0
    latency_avg: float = 0.0
    latency_min: float = 0.0
    latency_max: float = 0.0
    connect_time_avg: float = 0.0
    connect_time_max: float = 0.0
    peak_tps: float = 0.0
    total_sent_bytes: int = 0
    total_received_bytes: int = 0
    apdex: float = 1.0
    actual_tps: float = 0.0
    error_rate: float = 0.0
    error_type_timeout: int = 0
    error_type_connect_error: int = 0
    error_type_client_error: int = 0
    error_type_http_4xx: int = 0
    error_type_http_5xx: int = 0
    error_type_assertion: int = 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
    scenario_type: Optional[str] = None
    target_url: str
    project_id: Optional[str] = None
    total_requests: int = 0
    actual_tps: float = 0.0
    peak_tps: float = 0.0
    avg_response_time: float = 0.0
    p95_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
    execution_id: Optional[str] = Field(None, description="执行记录ID")
    status: str

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


# ==================== 执行历史 ====================

class PerformanceExecutionListItem(BaseModel):
    """执行历史列表项"""
    id: str = Field(..., description="执行ID")
    task_id: str = Field(..., description="任务ID")
    task_name: str = Field(..., description="任务名")
    project_id: Optional[str] = Field(None, description="项目ID")
    status: str = Field(..., description="状态")
    start_time: Optional[str] = Field(None, description="开始时间")
    end_time: Optional[str] = Field(None, description="结束时间")
    duration_actual: float = Field(0.0, description="实际时长(秒)")
    total_requests: int = Field(0, description="总请求数")
    actual_tps: float = Field(0.0, description="实际TPS")
    avg_response_time: float = Field(0.0, description="平均响应时间(ms)")
    p95_response_time: float = Field(0.0, description="P95响应时间(ms)")
    error_rate: float = Field(0.0, description="错误率")
    triggered_by: str = Field("manual", description="触发方式")
    snapshot_count: int = Field(0, description="快照条数")

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


class PerformanceExecutionListResponse(BaseModel):
    """执行历史列表响应"""
    total: int = Field(..., description="总数")
    items: List[PerformanceExecutionListItem] = Field(..., description="列表")

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


class PerformanceExecutionDetailResponse(BaseModel):
    """执行历史详情响应"""
    id: str = Field(..., description="执行ID")
    task_id: str = Field(..., description="任务ID")
    task_name: str = Field(..., description="任务名")
    project_id: Optional[str] = Field(None, description="项目ID")
    status: str = Field(..., description="状态")
    error_message: Optional[str] = Field(None, description="失败原因")
    start_time: Optional[str] = Field(None, description="开始时间")
    end_time: Optional[str] = Field(None, description="结束时间")
    duration_actual: float = Field(0.0, description="实际时长(秒)")
    total_requests: int = Field(0, description="总请求数")
    success_count: int = Field(0, description="成功请求数")
    fail_count: int = Field(0, description="失败请求数")
    error_rate: float = Field(0.0, description="错误率")
    actual_tps: float = Field(0.0, description="实际TPS")
    peak_tps: float = Field(0.0, description="峰值TPS")
    min_response_time: float = Field(0.0, description="最小响应时间(ms)")
    max_response_time: float = Field(0.0, description="最大响应时间(ms)")
    avg_response_time: float = Field(0.0, description="平均响应时间(ms)")
    p50_response_time: float = Field(0.0, description="P50响应时间(ms)")
    p90_response_time: float = Field(0.0, description="P90响应时间(ms)")
    p95_response_time: float = Field(0.0, description="P95响应时间(ms)")
    p99_response_time: float = Field(0.0, description="P99响应时间(ms)")
    std_dev: float = Field(0.0, description="标准差")
    latency_avg: float = Field(0.0, description="平均延迟(ms)")
    latency_min: float = Field(0.0, description="最小延迟(ms)")
    latency_max: float = Field(0.0, description="最大延迟(ms)")
    connect_time_avg: float = Field(0.0, description="平均连接时间(ms)")
    connect_time_max: float = Field(0.0, description="最大连接时间(ms)")
    apdex: float = Field(0.0, description="Apdex指数")
    total_sent_bytes: int = Field(0, description="发送字节数")
    total_received_bytes: int = Field(0, description="接收字节数")
    resource_summary: Optional[Any] = Field(None, description="执行机资源汇总")
    target_resource_summary: Optional[Any] = Field(None, description="目标机资源汇总")
    transaction_summary: Optional[Any] = Field(None, description="事务汇总")
    api_summary: Optional[Any] = Field(None, description="接口维度汇总")
    snapshot_count: int = Field(0, description="快照条数")
    triggered_by: str = Field("manual", description="触发方式")
    batch_id: Optional[str] = Field(None, description="关联批次ID")
    created_at: Optional[str] = Field(None, description="创建时间")

    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
    p95_response_time: float = 0.0
    p99_response_time: float = 0.0
    std_dev: float = 0.0
    latency_avg: float = 0.0
    connect_time_avg: float = 0.0
    sent_bytes: int = 0
    received_bytes: int = 0
    peak_tps: 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
    scenario_type: Optional[str] = None
    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
    peak_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
    p95_response_time: float = 0.0
    p99_response_time: float = 0.0
    std_dev: float = 0.0
    latency_avg: float = 0.0
    latency_min: float = 0.0
    latency_max: float = 0.0
    connect_time_avg: float = 0.0
    connect_time_max: float = 0.0
    apdex: float = 1.0
    total_sent_bytes: int = 0
    total_received_bytes: int = 0
    sent_kb_per_sec: float = 0.0
    received_kb_per_sec: 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")
    error_type_timeout: int = 0
    error_type_connect_error: int = 0
    error_type_client_error: int = 0
    error_type_http_4xx: int = 0
    error_type_http_5xx: int = 0
    error_type_assertion: int = 0

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


class PerformanceReportResponse(BaseModel):
    """性能测试报告完整响应"""
    summary: PerformanceReportSummary
    metrics: PerformanceReportMetrics
    snapshots: List[PerformanceSnapshotResponse] = []
    resource_summary: Optional[Dict[str, Any]] = Field(None, alias="resourceSummary", description="执行机资源监控汇总")
    target_resource_summary: Optional[Dict[str, Any]] = Field(None, alias="targetResourceSummary", description="目标机资源监控汇总")
    transaction_summary: Optional[Dict[str, Any]] = Field(None, alias="transactionSummary", description="事务处理时间汇总")
    api_summary: Optional[List[Dict[str, Any]]] = Field(None, alias="apiSummary", description="接口维度指标汇总")

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


class PerformanceExecutionReportResponse(BaseModel):
    """执行记录报告响应（与 PerformanceReportResponse 结构一致）"""
    summary: PerformanceReportSummary = Field(..., description="执行摘要")
    metrics: PerformanceReportMetrics = Field(..., description="指标统计")
    snapshots: List[PerformanceSnapshotResponse] = Field(default_factory=list, description="快照数据")
    resource_summary: Optional[Any] = Field(None, description="执行机资源汇总")
    target_resource_summary: Optional[Any] = Field(None, description="目标机资源汇总")
    transaction_summary: Optional[Any] = Field(None, description="事务汇总")
    api_summary: Optional[Any] = Field(None, description="接口维度汇总")

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


# ==================== AI 分析 ====================

class AiAnalysisCompareRequest(BaseModel):
    """多版本对比 AI 分析请求"""
    execution_ids: List[str] = Field(..., min_length=2, description="待对比的执行记录 ID 列表（至少 2 个）")

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


class AiAnalysisResponse(BaseModel):
    """AI 分析响应"""
    execution_id: str = Field("", description="执行记录 ID（对比分析时为逗号拼接）")
    analysis_type: str = Field("single", description="分析类型: single / comparison")
    overall_verdict: str = Field("", description="总体评价（Markdown）")
    key_findings: List[Dict[str, Any]] = Field(default_factory=list, description="关键发现")
    bottlenecks: List[Dict[str, Any]] = Field(default_factory=list, description="瓶颈分析")
    suggestions: List[Dict[str, Any]] = Field(default_factory=list, description="优化建议")
    resource_analysis: Optional[str] = Field(None, description="资源分析（Markdown）")
    trend_analysis: Optional[Dict[str, Any]] = Field(None, description="趋势分析")
    comparison: Optional[List[Dict[str, Any]]] = Field(None, description="多版本对比明细")
    raw_response: Optional[str] = Field(None, description="Claude 原始响应（调试用）")
    source: str = Field("ai", description="分析来源: ai / rule")

    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)


# ==================== curl 解析 ====================

class CurlParseRequest(BaseModel):
    """curl 命令解析请求"""
    # 注意：不加 min_length=1 —— 空字符串需由 parse_curl() 抛出 ValueError，经路由转为 400
    #（PRD 边界约定：空 curl 命令 → 400 提示；若加 min_length，Pydantic 会先返回 422）
    curl_command: str = Field(..., max_length=10000, description="完整 curl 命令")

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


class CurlParseResponse(BaseModel):
    """curl 命令解析响应"""
    method: str = "GET"
    target_url: str = ""
    headers: Dict[str, str] = Field(default_factory=dict)
    body: Optional[Any] = None
    auth_required: bool = False
    sign_request: bool = False
    cookie: Optional[str] = None
    errors: List[str] = Field(default_factory=list)

    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)


# ==================== 性能测试项目 ====================

class PerformanceProjectCreate(BaseModel):
    """创建性能测试项目"""
    name: str = Field(..., min_length=1, max_length=200, description="项目名称")
    description: str = Field("", description="项目描述")
    project_type: str = Field("standard", pattern=r"^(standard|custom)$", description="类型: standard/custom")
    icon: str = Field("folder", max_length=50, description="项目图标")
    sort_order: int = Field(0, description="排序序号")

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


class PerformanceProjectUpdate(BaseModel):
    """更新性能测试项目（所有字段可选）"""
    name: Optional[str] = Field(None, min_length=1, max_length=200, description="项目名称")
    description: Optional[str] = Field(None, description="项目描述")
    project_type: Optional[str] = Field(None, pattern=r"^(standard|custom)$", description="类型: standard/custom")
    icon: Optional[str] = Field(None, max_length=50, description="项目图标")
    sort_order: Optional[int] = Field(None, description="排序序号")

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


class PerformanceProjectResponse(BaseModel):
    """性能测试项目响应"""
    id: str
    name: str
    description: str = ""
    project_type: str = "standard"
    icon: str = "folder"
    sort_order: int = 0
    # 统计信息（列表接口附带）
    task_count: int = 0
    last_run_status: Optional[str] = None
    last_run_time: Optional[str] = None
    created_at: Optional[str] = None
    updated_at: Optional[str] = None

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


class PerformanceProjectListResponse(BaseModel):
    """性能测试项目列表响应"""
    total: int
    items: List[PerformanceProjectResponse]

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


class PerformanceProjectStatsResponse(BaseModel):
    """性能测试项目统计响应"""
    project_id: str
    task_count: int = 0
    status_distribution: Dict[str, int] = Field(default_factory=dict)
    last_run_status: Optional[str] = None
    last_run_time: Optional[str] = None

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


# ==================== 批量执行 ====================

class BatchRunRequest(BaseModel):
    """批量执行请求"""
    task_ids: List[str] = Field(..., min_length=1, description="要执行的任务ID列表")
    project_id: Optional[str] = Field(None, description="关联项目ID（可选）")

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


class BatchRunResponse(BaseModel):
    """批量执行响应"""
    message: str
    batch_id: str
    task_count: int
    task_ids: List[str] = Field(default_factory=list, description="本次批量执行的任务ID列表")
    report_id: Optional[str] = Field(None, description="合并报告ID（批量执行完成后生成）")

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


class BatchTaskItem(BaseModel):
    """批量执行详情中的任务状态项"""
    task_id: str = Field(..., description="任务ID")
    name: str = Field("", description="任务名称")
    status: str = Field("pending", description="任务状态: pending/running/completed/failed")
    actual_tps: Optional[float] = Field(None, description="实际TPS")
    avg_response_time: Optional[float] = Field(None, description="平均响应时间(ms)")
    error_rate: Optional[float] = Field(None, description="错误率")
    actual_concurrency: Optional[int] = Field(None, description="实际并发数")
    duration_actual: Optional[float] = Field(None, description="实际执行时长(秒)")

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


class BatchDetailResponse(BaseModel):
    """批量执行详情响应"""
    batch_id: str = Field(..., description="批次ID")
    project_id: Optional[str] = Field(None, description="项目ID")
    project_name: str = Field("", description="项目名称")
    status: str = Field("running", description="批次状态: running/completed/failed")
    total_count: int = Field(0, description="任务总数")
    success_count: int = Field(0, description="成功数")
    fail_count: int = Field(0, description="失败数")
    started_at: Optional[datetime] = Field(None, description="开始时间")
    completed_at: Optional[datetime] = Field(None, description="结束时间")
    tasks: List[BatchTaskItem] = Field(default_factory=list, description="任务状态列表")

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


# ==================== 合并报告 ====================

class TaskSummaryItem(BaseModel):
    """合并报告中的任务明细项"""
    task_id: str = Field(..., description="任务ID")
    task_name: str = Field("", description="任务名称")
    status: str = Field("", description="任务状态")
    total_requests: int = Field(0, description="请求数")
    success_count: int = Field(0, description="成功数")
    fail_count: int = Field(0, description="失败数")
    avg_response_time: float = Field(0.0, description="平均响应时间(ms)")
    actual_tps: float = Field(0.0, description="实际TPS")
    error_rate: float = Field(0.0, description="错误率")

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


class ProjectReportSummary(BaseModel):
    """合并报告聚合指标摘要"""
    total_requests: int = 0
    success_count: int = 0
    fail_count: int = 0
    error_rate: float = 0.0
    actual_tps: float = 0.0
    peak_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
    p95_response_time: float = 0.0
    p99_response_time: float = 0.0
    std_dev: float = 0.0
    apdex: float = 1.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")
    total_sent_bytes: int = 0
    total_received_bytes: int = 0
    duration_actual: float = 0.0

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


class ProjectReportResponse(BaseModel):
    """合并报告完整响应"""
    id: str
    project_id: str
    batch_id: Optional[str] = None
    created_at: Optional[str] = None
    summary: ProjectReportSummary
    task_summaries: List[TaskSummaryItem] = []

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


class ProjectReportListResponse(BaseModel):
    """合并报告列表响应"""
    total: int
    items: List[ProjectReportResponse]

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