#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：door_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 DoorSimulator(BaseSimulator):
    """
    门口屏模拟器

    模拟门口屏设备，支持：
    - 设备注册与状态上报
    - 门禁事件（开门/关门/超时未关/非法闯入）
    - 呼叫记录（访客呼叫、业主应答、呼叫超时）
    - 接收平台开锁指令

    Attributes:
        _door_status (str): 门状态 (open/closed)
        _battery_level (int): 电池电量 (0-100)
        _call_active (bool): 是否正在呼叫中
    """

    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': 30, 'enabled': True}
            topics: 多主题前缀映射
            topic_params: 主题动态参数
        """
        super().__init__(device_id, env_config_id, "door", mqtt_manager,
                         report_config, topics, topic_params)
        self._door_status = "closed"
        self._battery_level = random.randint(60, 100)
        self._call_active = False

    def build_register_payload(self) -> dict:
        """构建设备注册消息"""
        return {
            "device_id": self.device_id,
            "device_type": "door_station",
            "name": f"门口屏-{self.device_id}",
            "model": "DS-KD8003",
            "version": "V2.1.6",
            "location": f"单元门-{random.choice(['东', '南', '西', '北'])}",
            "capabilities": ["door_control", "video_call", "card_reader", "password"]
        }

    def build_status_payload(self) -> dict:
        """构建设备状态上报消息"""
        # 模拟电池缓慢下降
        self._battery_level = max(10, self._battery_level - random.randint(0, 2))
        # 偶尔模拟门状态变化
        if random.random() < 0.1:
            self._door_status = "open" if self._door_status == "closed" else "closed"

        return {
            "device_id": self.device_id,
            "status": "online",
            "door_status": self._door_status,
            "battery": self._battery_level,
            "signal": random.randint(70, 100),
            "temperature": round(random.uniform(25, 40), 1),
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        }

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

        支持的指令：
        - unlock: 远程开锁
        - lock: 远程锁门
        - reboot: 重启设备
        - set_volume: 设置音量
        """
        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 == "unlock":
                self._door_status = "open"
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "unlock",
                    "result": "success",
                    "message": "门已打开"
                })
                # 模拟5秒后自动关门
                threading_timer = __import__('threading').Timer
                threading_timer(5.0, self._auto_close_door).start()

            elif command == "lock":
                self._door_status = "closed"
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "lock",
                    "result": "success",
                    "message": "门已锁定"
                })

            elif command == "reboot":
                self._notify_report(response_topic, {
                    "device_id": self.device_id,
                    "command": "reboot",
                    "result": "success",
                    "message": "设备正在重启"
                })
                # 模拟重启（短暂离线后恢复）
                self._simulate_reboot()

            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 _auto_close_door(self) -> None:
        """模拟自动关门"""
        self._door_status = "closed"
        if self._has_real_topics:
            publish_topics = self.get_publish_topics()
            status_topic = publish_topics[0]["topic"] if publish_topics else self.get_topic_prefix()
        else:
            status_topic = f"{self.get_topic_prefix()}/{self.device_id}/status"
        self.mqtt.publish(self.env_config_id, status_topic, {
            "device_id": self.device_id,
            "status": "online",
            "door_status": "closed",
            "event": "auto_close"
        })

    def _simulate_reboot(self) -> None:
        """模拟设备重启"""
        import threading as t
        # 发送离线
        if self._has_real_topics:
            publish_topics = self.get_publish_topics()
            offline_topic = publish_topics[0]["topic"] if publish_topics else self.get_topic_prefix()
        else:
            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": "reboot"
        })
        # 5秒后恢复
        def _recover():
            time.sleep(5)
            if self._running:
                if self._has_real_topics:
                    publish_topics = self.get_publish_topics()
                    status_topic = publish_topics[0]["topic"] if publish_topics else self.get_topic_prefix()
                else:
                    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=_recover, daemon=True).start()

    def trigger_event(self, event_type: str = "random") -> bool:
        """
        触发门禁事件

        Args:
            event_type: 事件类型 (random/door_open/door_close/timeout/intrusion)

        Returns:
            bool: 是否上报成功
        """
        events = {
            "door_open": {
                "event": "door_open",
                "method": random.choice(["card", "password", "remote", "fingerprint"]),
                "card_id": f"card_{random.randint(1000, 9999)}",
                "user": f"user_{random.randint(1, 100)}"
            },
            "door_close": {
                "event": "door_close",
                "method": "auto",
                "duration_seconds": random.randint(5, 60)
            },
            "timeout": {
                "event": "door_timeout",
                "duration_seconds": random.randint(30, 120),
                "alarm": True
            },
            "intrusion": {
                "event": "illegal_intrusion",
                "alarm": True,
                "severity": "high"
            }
        }

        if event_type == "random":
            event_type = random.choice(list(events.keys()))

        payload = events.get(event_type, events["door_open"])
        payload["device_id"] = self.device_id
        payload["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")

        return self.report("event", payload)

    def trigger_call(self, call_type: str = "random") -> bool:
        """
        触发呼叫记录

        Args:
            call_type: 呼叫类型 (random/incoming/answered/timeout/canceled)

        Returns:
            bool: 是否上报成功
        """
        calls = {
            "incoming": {
                "call_type": "incoming",
                "caller": f"visitor_{random.randint(100, 999)}",
                "room": f"{random.randint(1, 30)}-{random.randint(1, 20)}"
            },
            "answered": {
                "call_type": "answered",
                "caller": f"visitor_{random.randint(100, 999)}",
                "room": f"{random.randint(1, 30)}-{random.randint(1, 20)}",
                "duration": random.randint(10, 120)
            },
            "timeout": {
                "call_type": "timeout",
                "caller": f"visitor_{random.randint(100, 999)}",
                "room": f"{random.randint(1, 30)}-{random.randint(1, 20)}",
                "timeout_seconds": 30
            },
            "canceled": {
                "call_type": "canceled",
                "caller": f"visitor_{random.randint(100, 999)}",
                "reason": "visitor_canceled"
            }
        }

        if call_type == "random":
            call_type = random.choice(list(calls.keys()))

        payload = calls.get(call_type, calls["incoming"])
        payload["device_id"] = self.device_id
        payload["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")

        return self.report("call", payload)