#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：deploy.py
模块描述：自动化部署测试模块 Pydantic 模式定义

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

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


# ==================== 工具函数 ====================

def to_camel(string: str) -> str:
    """Convert snake_case to camelCase"""
    components = string.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])


# ==================== 服务器 Schema ====================

class DeployServerBase(BaseModel):
    """服务器基础模式"""
    name: str = Field(..., min_length=1, max_length=100, description="服务器名称")
    host: str = Field(..., min_length=1, max_length=255, description="主机地址")
    port: int = Field(default=22, ge=1, le=65535, description="SSH 端口")
    username: str = Field(..., min_length=1, max_length=100, description="SSH 登录用户名")
    password: Optional[str] = Field(default=None, max_length=500, description="SSH 密码")
    auth_type: str = Field(default="password", description="认证类型: password/key")
    private_key: Optional[str] = Field(default=None, description="SSH 私钥内容")
    description: Optional[str] = Field(default=None, max_length=500, description="备注描述")

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


class DeployServerCreate(DeployServerBase):
    """创建服务器请求"""
    pass


class DeployServerUpdate(BaseModel):
    """更新服务器请求（所有字段可选）"""
    name: Optional[str] = Field(default=None, min_length=1, max_length=100, description="服务器名称")
    host: Optional[str] = Field(default=None, min_length=1, max_length=255, description="主机地址")
    port: Optional[int] = Field(default=None, ge=1, le=65535, description="SSH 端口")
    username: Optional[str] = Field(default=None, min_length=1, max_length=100, description="SSH 登录用户名")
    password: Optional[str] = Field(default=None, max_length=500, description="SSH 密码（留空不修改）")
    auth_type: Optional[str] = Field(default=None, description="认证类型: password/key")
    private_key: Optional[str] = Field(default=None, description="SSH 私钥内容")
    description: Optional[str] = Field(default=None, max_length=500, description="备注描述")

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


class DeployServerResponse(DeployServerBase):
    """服务器响应"""
    id: str = Field(..., description="服务器 ID")
    status: str = Field(..., description="连接状态")
    created_at: Optional[datetime] = Field(default=None, description="创建时间")
    updated_at: Optional[datetime] = Field(default=None, description="更新时间")

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


class DeployServerListResponse(BaseModel):
    """服务器列表响应"""
    items: List[DeployServerResponse] = Field(default=[], description="服务器列表")
    total: int = Field(default=0, description="总数")


# ==================== 脚本 Schema ====================

class ExpectAnswer(BaseModel):
    """交互式应答规则"""
    trigger: str = Field(..., min_length=1, max_length=500, description="触发提示文本")
    trigger_type: str = Field(default="contains", description="匹配方式: contains/regex")
    answer: str = Field(..., description="应答内容")
    timeout: int = Field(default=30, ge=1, description="超时时间（秒）")
    order: int = Field(default=0, ge=0, description="匹配顺序")
    sensitive: bool = Field(default=False, description="是否敏感信息")
    description: Optional[str] = Field(default=None, max_length=200, description="规则描述")


class DeployScriptBase(BaseModel):
    """脚本基础模式"""
    name: str = Field(..., min_length=1, max_length=200, description="脚本配置名称")
    description: Optional[str] = Field(default=None, max_length=500, description="描述")
    server_id: str = Field(..., description="关联的目标服务器 ID")
    remote_command: str = Field(..., min_length=1, max_length=1000, description="远程执行命令")
    work_dir: Optional[str] = Field(default=None, max_length=500, description="远程工作目录")
    timeout: int = Field(default=3600, ge=60, description="执行超时时间（秒）")
    expect_answers: List[ExpectAnswer] = Field(default=[], description="交互式应答规则")

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


class DeployScriptCreate(DeployScriptBase):
    """创建脚本请求"""
    pass


class DeployScriptUpdate(BaseModel):
    """更新脚本请求（所有字段可选）"""
    name: Optional[str] = Field(default=None, min_length=1, max_length=200, description="脚本配置名称")
    description: Optional[str] = Field(default=None, max_length=500, description="描述")
    server_id: Optional[str] = Field(default=None, description="关联的目标服务器 ID")
    remote_command: Optional[str] = Field(default=None, min_length=1, max_length=1000, description="远程执行命令")
    work_dir: Optional[str] = Field(default=None, max_length=500, description="远程工作目录")
    timeout: Optional[int] = Field(default=None, ge=60, description="执行超时时间（秒）")
    expect_answers: Optional[List[ExpectAnswer]] = Field(default=None, description="交互式应答规则")

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


class DeployScriptResponse(DeployScriptBase):
    """脚本响应"""
    id: str = Field(..., description="脚本 ID")
    server_name: str = Field(default="", description="服务器名称")
    created_at: Optional[datetime] = Field(default=None, description="创建时间")
    updated_at: Optional[datetime] = Field(default=None, description="更新时间")

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


class DeployScriptListResponse(BaseModel):
    """脚本列表响应"""
    items: List[DeployScriptResponse] = Field(default=[], description="脚本列表")
    total: int = Field(default=0, description="总数")


# ==================== 执行记录 Schema ====================

class DeployExecutionCreate(BaseModel):
    """创建执行记录请求"""
    script_id: str = Field(..., description="脚本配置 ID")
    trigger_by: str = Field(default="user", description="触发人")

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


class DeployExecutionResponse(BaseModel):
    """执行记录响应"""
    id: str = Field(..., description="执行记录 ID")
    script_id: str = Field(..., description="脚本配置 ID")
    server_id: str = Field(..., description="服务器 ID")
    script_name: str = Field(..., description="脚本名称")
    server_name: str = Field(..., description="服务器名称")
    server_host: str = Field(..., description="服务器地址")
    remote_command: str = Field(..., description="执行的命令")
    status: str = Field(..., description="状态")
    start_time: Optional[datetime] = Field(default=None, description="开始时间")
    end_time: Optional[datetime] = Field(default=None, description="结束时间")
    duration: float = Field(default=0.0, description="耗时（秒）")
    exit_code: Optional[int] = Field(default=None, description="退出码")
    error_message: Optional[str] = Field(default=None, description="错误信息")
    trigger_by: str = Field(default="", description="触发人")
    created_at: Optional[datetime] = Field(default=None, description="创建时间")

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


class DeployExecutionListResponse(BaseModel):
    """执行记录列表响应"""
    items: List[DeployExecutionResponse] = Field(default=[], description="执行记录列表")
    total: int = Field(default=0, description="总数")


# ==================== 日志 Schema ====================

class DeployLogResponse(BaseModel):
    """日志响应"""
    id: str = Field(..., description="日志 ID")
    execution_id: str = Field(..., description="执行记录 ID")
    timestamp: Optional[datetime] = Field(default=None, description="日志时间")
    level: str = Field(..., description="日志级别")
    message: str = Field(..., description="日志内容")
    is_sensitive: bool = Field(default=False, description="是否敏感信息")

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


class DeployLogListResponse(BaseModel):
    """日志列表响应"""
    items: List[DeployLogResponse] = Field(default=[], description="日志列表")
    total: int = Field(default=0, description="总数")


# ==================== 连接测试 Schema ====================

class TestConnectionResponse(BaseModel):
    """连接测试响应"""
    success: bool = Field(..., description="是否成功")
    message: str = Field(..., description="提示信息")
    server_name: str = Field(default="", description="服务器名称")
    host: str = Field(default="", description="主机地址")
    port: int = Field(default=22, description="端口")