#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：client_simulator.py
模块描述：集控客户端模拟器，模拟设备注册、心跳、远程控制

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

import json
import logging
import random
import time
from typing import Optional

from app.simulators.base_simulator import BaseSimulator
from app.services.mqtt_manager import MqttManager

logger = logging.getLogger(__name__)


class ClientSimulator(BaseSimulator):
    """
    集控客户端模拟器

    模拟集控客户端设备，支持：
    - 设备注册与心跳保活（5秒间隔）
    - 远程控制指令响应
    - 运行日志上报
    - 版本信息上报
    - 固件升级流程模拟

    Attributes:
        _version (str): 当前版本号
        _heartbeat_count (int): 心跳计数
        _log_level (str): 日志级别
    """

    # 版本历史
    _VERSIONS = ["V1.2.0", "V1.3.0", "V1.4.0", "V2.0.0", "V2.1.0"]

    def __init__(self, device_id: str, env_config_id: str,
                 mqtt_manager: MqttManager, report_config: Optional[dict] = None,
                 topics: Optional[dict] = None,
                 topic_params: Optional[dict] = None):
        """
        初始化集控客户端模拟器

        Args:
            device_id: 设备 ID
            env_config_id: 环境配置 ID
            mqtt_manager: MQTT 管理器
            report_config: 上报配置，如 {'interval': 5, 'enabled': True}
            topics: 多主题前缀映射
            topic_params: 主题动态参数
        """
        super().__init__(device_id, env_config_id, "client", mqtt_manager,
                         report_config, topics, topic_params)
        self._version = random.choice(self._VERSIONS)
        self._heartbeat_count = 0
        self._log_level = "info"
        self._firmware_updating = False

    def build_register_payload(self) -> dict:
        """构建设备注册消息"""
        return {
            "device_id": self.device_id,
            "device_type": "control_client",
            "name": f"集控客户端-{self.device_id}",
            "model": "CC-Client-Pro",
            "version": self._version,
            "os": "Windows 10 Enterprise",
            "os_version": "22H2",
            "architecture": "x86_64",
            "capabilities": ["heartbeat", "remote_control", "log_report", "firmware_upgrade"],
            "network": {
                "ip": f"192.168.{random.randint(1, 254)}.{random.randint(1, 254)}",
                "mac": ":".join([f"{random.randint(0,255):02x}" for _ in range(6)])
            }
        }

    def build_status_payload(self) -> dict:
        """构建设备状态上报消息"""
        self._heartbeat_count += 1

        return {
            "device_id": self.device_id,
            "status": "online",
            "version": self._version,
            "uptime_seconds": self._heartbeat_count * self._report_interval,
            "cpu_usage": random.randint(10, 90),
            "memory_usage": random.randint(20, 80),
            "disk_usage": random.randint(30, 70),
            "network_status": "connected",
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        }

    def _on_command(self, topic: str, payload: dict) -> None:
        """
        处理平台下发的指令

        支持的指令：
        - remote_restart: 远程重启
        - remote_shutdown: 远程关机
        - remote_lock: 远程锁定
        - update_firmware: 固件升级
        - set_log_level: 设置日志级别
        - collect_log: 收集日志
        """
        try:
            command = payload.get("command", "")
            logger.info(f"集控客户端收到指令: device_id={self.device_id}, command={command}")

            # 记录接收到的平台下发指令（direction=subscribe）
            command_topic = f"{self.get_topic_prefix()}/{self.device_id}/command"
            self._notify_report(
                command_topic,
                payload,
                direction="subscribe",
                status="success"
            )

            response_topic = f"{self.get_topic_prefix()}/{self.device_id}/command_response"

            if command == "remote_restart":
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "remote_restart",
                    "result": "success",
                    "message": "设备将在30秒后重启",
                    "delay_seconds": 30
                })
                self._simulate_restart()

            elif command == "remote_shutdown":
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "remote_shutdown",
                    "result": "success",
                    "message": "设备正在关机",
                    "delay_seconds": 10
                })
                self._simulate_shutdown()

            elif command == "remote_lock":
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "remote_lock",
                    "result": "success",
                    "message": "设备已锁定"
                })

            elif command == "update_firmware":
                version = payload.get("version", "V2.2.0")
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "update_firmware",
                    "result": "success",
                    "message": f"开始固件升级: {self._version} -> {version}",
                    "target_version": version
                })
                self._simulate_firmware_update(version)

            elif command == "set_log_level":
                level = payload.get("level", "info")
                if level in ("debug", "info", "warning", "error"):
                    self._log_level = level
                    self._notify_report(response_topic, {
                        "device_id": self.device_id,
                        "command": "set_log_level",
                        "result": "success",
                        "level": level
                    })
                else:
                    self._notify_report(response_topic, {
                        "device_id": self.device_id,
                        "command": "set_log_level",
                        "result": "failed",
                        "message": f"无效的日志级别: {level}"
                    })

            elif command == "collect_log":
                log_content = self._generate_logs()
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "collect_log",
                    "result": "success",
                    "log_count": len(log_content),
                    "logs": log_content
                })

            else:
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": command,
                    "result": "unknown",
                    "message": f"不支持的指令: {command}"
                })

        except Exception as e:
            logger.error(f"集控客户端指令处理异常: {e}")

    def _simulate_restart(self) -> None:
        """模拟设备重启"""
        import threading as t

        def _restart():
            time.sleep(30)
            # 发送离线
            offline_topic = f"{self.get_topic_prefix()}/{self.device_id}/status"
            self.mqtt.publish(self.env_config_id, offline_topic, {
                "device_id": self.device_id, "status": "offline", "reason": "restart"
            })
            time.sleep(10)
            # 恢复在线
            if self._running:
                status_topic = f"{self.get_topic_prefix()}/{self.device_id}/status"
                self.mqtt.publish(self.env_config_id, status_topic, self.build_status_payload())

        t.Thread(target=_restart, daemon=True).start()

    def _simulate_shutdown(self) -> None:
        """模拟设备关机"""
        import threading as t

        def _shutdown():
            time.sleep(10)
            self._running = False
            offline_topic = f"{self.get_topic_prefix()}/{self.device_id}/status"
            self.mqtt.publish(self.env_config_id, offline_topic, {
                "device_id": self.device_id, "status": "offline", "reason": "shutdown"
            })

        t.Thread(target=_shutdown, daemon=True).start()

    def _simulate_firmware_update(self, target_version: str) -> None:
        """模拟固件升级"""
        import threading as t

        def _update():
            self._firmware_updating = True
            stages = [
                ("downloading", 30, 30),
                ("installing", 60, 70),
                ("rebooting", 20, 95),
                ("completed", 10, 100)
            ]
            for stage, duration, progress in stages:
                if not self._running:
                    break
                time.sleep(duration)
                # 上报升级进度
                update_topic = f"{self.get_topic_prefix()}/{self.device_id}/update_progress"
                self.mqtt.publish(self.env_config_id, update_topic, {
                    "device_id": self.device_id,
                    "stage": stage,
                    "progress": progress,
                    "target_version": target_version
                })

            if self._running:
                self._version = target_version
                self._firmware_updating = False
                logger.info(f"集控客户端固件升级完成: {self.device_id} -> {target_version}")

        t.Thread(target=_update, daemon=True).start()

    def _generate_logs(self) -> list:
        """生成模拟日志"""
        log_types = ["info", "warning", "error"]
        log_messages = [
            "服务启动成功",
            "配置文件加载完成",
            "MQTT 连接正常",
            "心跳上报成功",
            "内存使用率正常",
            "网络连接状态良好",
            "检测到系统更新",
            "定时任务执行完成",
            "用户登录成功",
            "缓存清理完成",
        ]

        return [
            {
                "level": random.choice(log_types),
                "message": random.choice(log_messages),
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
                "source": f"client_{self.device_id[:8]}"
            }
            for _ in range(random.randint(3, 10))
        ]

    def trigger_heartbeat(self) -> bool:
        """
        手动触发心跳上报

        Returns:
            bool: 是否成功
        """
        heartbeat_topic = f"{self.get_topic_prefix()}/{self.device_id}/heartbeat"
        payload = {
            "device_id": self.device_id,
            "heartbeat_count": self._heartbeat_count,
            "status": "online",
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        }
        success = self.mqtt.publish(self.env_config_id, heartbeat_topic, payload)
        self._notify_report(heartbeat_topic, payload, status="success" if success else "failed")
        return success

    def trigger_log_report(self, level: str = "info") -> bool:
        """
        手动触发日志上报

        Args:
            level: 日志级别

        Returns:
            bool: 是否成功
        """
        log_types = {"info": "信息日志", "warning": "警告日志", "error": "错误日志"}
        log_topic = f"{self.get_topic_prefix()}/{self.device_id}/log"
        payload = {
            "device_id": self.device_id,
            "level": level,
            "type": log_types.get(level, "info"),
            "logs": self._generate_logs(),
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        }
        success = self.mqtt.publish(self.env_config_id, log_topic, payload)
        self._notify_report(log_topic, payload, status="success" if success else "failed")
        return success

    def trigger_version_report(self) -> bool:
        """
        手动触发版本上报

        Returns:
            bool: 是否成功
        """
        version_topic = f"{self.get_topic_prefix()}/{self.device_id}/version"
        payload = {
            "device_id": self.device_id,
            "current_version": self._version,
            "latest_version": self._VERSIONS[-1],
            "has_update": self._version != self._VERSIONS[-1],
            "release_date": "2026-07-15",
            "changelog": "优化系统稳定性，修复已知问题"
        }
        success = self.mqtt.publish(self.env_config_id, version_topic, payload)
        self._notify_report(version_topic, payload, status="success" if success else "failed")
        return success