#!/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 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 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=500, description="并发数")
    qps_target: Optional[int] = Field(default=None, ge=1, description="目标QPS（留空使用默认值100）")
    duration: int = Field(60, ge=1, le=3600, 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）")

    # 认证配置
    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="唯一性字段配置列表")

    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=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="使用的账号")
    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="唯一性字段配置列表")

    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

    # 结果统计
    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
    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
    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
    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
    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] = []

    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
    report_id: Optional[str] = Field(None, description="合并报告ID（批量执行完成后生成）")

    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)