#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：device_sim.py
模块描述：设备模拟模块 Pydantic 模式定义

作者：czj
创建日期：2026-07-29
最后修改：2026-07-29
"""

from datetime import datetime
from typing import Optional, List, Dict
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 EnvConfigBase(BaseModel):
    """环境配置基础模式"""

    name: str = Field(..., min_length=1, max_length=100, description="配置名称")
    broker_host: str = Field(..., min_length=1, max_length=255, description="Broker 地址")
    broker_port: int = Field(default=1883, ge=1, le=65535, description="端口号")
    username: Optional[str] = Field(default=None, max_length=100, description="MQTT 用户名")
    password: Optional[str] = Field(default=None, max_length=500, description="MQTT 密码")
    topic_prefix: str = Field(default="device", max_length=200, description="主题前缀（已弃用，建议使用 topics）")
    topics: Optional[Dict[str, str]] = Field(default=None, description="多主题前缀映射，key为设备类型，value为主题前缀")
    use_tls: bool = Field(default=False, description="是否启用 TLS")
    client_id_prefix: str = Field(default="sim", max_length=100, description="客户端 ID 前缀")

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


class EnvConfigCreate(EnvConfigBase):
    """创建环境配置请求"""
    pass


class EnvConfigUpdate(BaseModel):
    """更新环境配置请求"""

    name: Optional[str] = Field(default=None, min_length=1, max_length=100, description="配置名称")
    broker_host: Optional[str] = Field(default=None, min_length=1, max_length=255, description="Broker 地址")
    broker_port: Optional[int] = Field(default=None, ge=1, le=65535, description="端口号")
    username: Optional[str] = Field(default=None, max_length=100, description="MQTT 用户名")
    password: Optional[str] = Field(default=None, max_length=500, description="MQTT 密码")
    topic_prefix: Optional[str] = Field(default=None, max_length=200, description="主题前缀（已弃用，建议使用 topics）")
    topics: Optional[Dict[str, str]] = Field(default=None, description="多主题前缀映射")
    use_tls: Optional[bool] = Field(default=None, description="是否启用 TLS")
    client_id_prefix: Optional[str] = Field(default=None, max_length=100, description="客户端 ID 前缀")

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


class EnvConfigResponse(EnvConfigBase):
    """环境配置响应"""

    id: str = Field(..., description="配置 ID")
    status: str = Field(..., description="连接状态")
    last_connected_at: Optional[datetime] = Field(default=None, description="最后连接时间")
    created_at: datetime = Field(..., description="创建时间")
    updated_at: datetime = Field(..., description="更新时间")

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


class EnvConfigListResponse(BaseModel):
    """环境配置列表响应"""

    items: List[EnvConfigResponse] = Field(default=[], description="环境配置列表")
    total: int = Field(default=0, description="总数")


# ==================== 模拟设备 Schema ====================

class SimulatorBase(BaseModel):
    """模拟设备基础模式"""

    env_config_id: str = Field(..., description="关联环境配置 ID")
    device_type: str = Field(..., pattern="^(door|paperless|central|client)$", description="设备类型")
    device_name: str = Field(..., min_length=1, max_length=200, description="模拟设备名称")
    device_id: str = Field(..., min_length=1, max_length=200, description="模拟设备 ID")
    auto_reconnect: bool = Field(default=True, description="是否自动重连")
    extra_attrs: Optional[dict] = Field(default=None, description="设备自定义属性")

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


class SimulatorCreate(SimulatorBase):
    """创建模拟设备请求"""
    pass


class SimulatorUpdate(BaseModel):
    """更新模拟设备请求"""

    device_name: Optional[str] = Field(default=None, min_length=1, max_length=200, description="模拟设备名称")
    auto_reconnect: Optional[bool] = Field(default=None, description="是否自动重连")
    extra_attrs: Optional[dict] = Field(default=None, description="设备自定义属性")

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


class SimulatorResponse(SimulatorBase):
    """模拟设备响应"""

    id: str = Field(..., description="设备 ID")
    status: str = Field(..., description="运行状态")
    last_reported_at: Optional[datetime] = Field(default=None, description="最后上报时间")
    total_reports: int = Field(default=0, description="累计上报次数")
    created_at: datetime = Field(..., description="创建时间")
    updated_at: datetime = Field(..., description="更新时间")

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


class SimulatorListResponse(BaseModel):
    """模拟设备列表响应"""

    items: List[SimulatorResponse] = Field(default=[], description="模拟设备列表")
    total: int = Field(default=0, description="总数")


# ==================== 上报记录 Schema ====================

class ReportLogResponse(BaseModel):
    """上报记录响应"""

    id: str = Field(..., description="记录 ID")
    device_id: str = Field(..., description="关联设备 ID")
    topic: str = Field(..., description="MQTT 主题")
    payload: Optional[dict] = Field(default=None, description="上报数据")
    direction: str = Field(..., description="方向")
    status: str = Field(..., description="状态")
    error_message: Optional[str] = Field(default=None, description="错误信息")
    created_at: datetime = Field(..., description="创建时间")

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


class ReportLogListResponse(BaseModel):
    """上报记录列表响应"""

    items: List[ReportLogResponse] = Field(default=[], description="上报记录列表")
    total: int = Field(default=0, description="总数")


# ==================== 手动上报 Schema ====================

class ManualReportRequest(BaseModel):
    """手动上报请求"""

    topic: str = Field(..., min_length=1, max_length=500, description="上报主题")
    payload: dict = Field(default={}, description="上报数据内容")


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

class TestConnectionResponse(BaseModel):
    """连接测试响应"""

    success: bool = Field(..., description="是否成功")
    message: str = Field(default="", description="结果信息")
    latency_ms: Optional[int] = Field(default=None, alias="latencyMs", description="连接延迟(毫秒)")

    model_config = ConfigDict(
        populate_by_name=True,
    )