/**
 * 自然写互动课堂教学管理云平台软件 V1.0
 * 
 * 设备管理服务
 * 管理点阵笔、网关、终端设备、算力盒的全生命周期
 */
package com.writech.cloud.service;

import com.writech.cloud.model.Device;
import com.writech.cloud.controller.DeviceController.ClassroomTopology;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备服务类
 * 
 * 管理互动课堂中所有硬件设备的注册、绑定、状态监控
 * 设备类型：pen(点阵笔) / gateway(网关) / terminal(终端) / edge_box(算力盒)
 */
@Service
public class DeviceService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /** 设备在线超时时间（秒），超过此时间未收到心跳视为离线 */
    private static final long DEVICE_ONLINE_TIMEOUT = 120;

    /** 网关设备心跳间隔（秒） */
    private static final long GATEWAY_HEARTBEAT_INTERVAL = 30;

    /** 笔设备心跳间隔（秒） */
    private static final long PEN_HEARTBEAT_INTERVAL = 300;

    /**
     * 保存设备信息
     */
    @Transactional
    public void save(Device device) {
        // deviceRepository.save(device);
        // 更新Redis中的设备在线状态缓存
        updateDeviceOnlineStatus(device.getId(), true);
    }

    /**
     * 根据ID查询设备
     */
    public Device findById(String deviceId) {
        // return deviceRepository.findById(deviceId).orElse(null);
        return null;
    }

    /**
     * 根据MAC地址查询设备
     */
    public Device findByMacAddr(String macAddr) {
        // return deviceRepository.findByMacAddr(macAddr);
        return null;
    }

    /**
     * 校验设备证书（X.509）
     * 首次注册时网关设备需提供预置的设备证书进行身份校验
     * 
     * @param macAddr MAC地址
     * @param certPem PEM格式的X.509证书
     * @return 校验通过返回true
     */
    public boolean validateDeviceCertificate(String macAddr, String certPem) {
        if (certPem == null || certPem.isEmpty()) {
            return false;
        }

        try {
            // 解析X.509证书
            java.security.cert.CertificateFactory cf = 
                    java.security.cert.CertificateFactory.getInstance("X.509");
            java.io.ByteArrayInputStream bis = 
                    new java.io.ByteArrayInputStream(certPem.getBytes());
            X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);

            // 检查证书有效期
            cert.checkValidity();

            // 验证证书签名（使用CA根证书公钥）
            // cert.verify(caCertificate.getPublicKey());

            // 从证书CN字段提取MAC地址，与请求中的MAC地址比对
            String cn = cert.getSubjectX500Principal().getName();
            if (!cn.contains(macAddr.replace(":", "").toUpperCase())) {
                return false;
            }

            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 设备绑定
     * 将设备绑定至指定用户和教室
     */
    @Transactional
    public void bindDevice(String deviceId, String userId, String classroomId) {
        // deviceRepository.updateBinding(deviceId, userId, classroomId);
    }

    /**
     * 设备解绑
     */
    @Transactional
    public void unbindDevice(String deviceId) {
        // deviceRepository.clearBinding(deviceId);
    }

    /**
     * 分页查询设备列表
     * 支持按学校、教室、类型、状态多维度过滤
     */
    public Page<Device> queryDevices(String schoolId, String classroomId,
                                      String deviceType, Integer status,
                                      Pageable pageable) {
        // return deviceRepository.queryByConditions(schoolId, classroomId, 
        //         deviceType, status, pageable);
        return null;
    }

    /**
     * 更新设备心跳
     * 心跳数据写入MySQL并更新Redis在线状态缓存
     */
    public void updateHeartbeat(Device device) {
        // deviceRepository.updateHeartbeat(device.getId(), 
        //         device.getLastHeartbeat(), device.getBatteryLevel(),
        //         device.getConnectedPenCount(), device.getCpuUsage(),
        //         device.getMemoryUsage());

        // 更新Redis在线状态（设置过期时间为心跳超时时间）
        updateDeviceOnlineStatus(device.getId(), true);
    }

    /**
     * 构建教室设备拓扑
     * 查询教室内所有设备，按类型分组并建立连接关系
     * 
     * @param classroomId 教室ID
     * @return 拓扑结构（网关/算力盒/终端/笔）
     */
    public ClassroomTopology buildClassroomTopology(String classroomId) {
        // 查询教室下所有设备
        // List<Device> devices = deviceRepository.findByClassroomId(classroomId);
        List<Device> devices = new ArrayList<>();

        ClassroomTopology topology = new ClassroomTopology();
        topology.setClassroomId(classroomId);

        // 按设备类型分组
        Map<String, List<Device>> grouped = devices.stream()
                .collect(Collectors.groupingBy(Device::getType));

        topology.setGateways(grouped.getOrDefault("gateway", new ArrayList<>()));
        topology.setEdgeBoxes(grouped.getOrDefault("edge_box", new ArrayList<>()));
        topology.setTerminals(grouped.getOrDefault("terminal", new ArrayList<>()));
        topology.setPens(grouped.getOrDefault("pen", new ArrayList<>()));
        topology.setTotalDeviceCount(devices.size());

        return topology;
    }

    /**
     * 批量检查设备在线状态
     * 通过Redis缓存快速判断设备是否在线
     */
    public Map<String, Boolean> checkOnlineStatus(List<String> deviceIds) {
        Map<String, Boolean> result = new HashMap<>();
        for (String deviceId : deviceIds) {
            String key = "writech:device:online:" + deviceId;
            result.put(deviceId, Boolean.TRUE.equals(redisTemplate.hasKey(key)));
        }
        return result;
    }

    /**
     * 发送远程指令至设备
     * 通过MQTT向指定设备下发控制指令（重启/配置更新/OTA等）
     */
    public void sendCommand(String deviceId, String command, Map<String, Object> params) {
        // 构建MQTT消息
        Map<String, Object> message = new HashMap<>();
        message.put("command", command);
        message.put("params", params);
        message.put("timestamp", System.currentTimeMillis());

        // 根据设备类型确定Topic
        Device device = findById(deviceId);
        if (device == null) return;

        String topic;
        switch (device.getType()) {
            case "gateway":
                topic = "gateway/" + deviceId + "/command";
                break;
            case "edge_box":
                topic = "edgebox/" + deviceId + "/command";
                break;
            default:
                topic = "device/" + deviceId + "/command";
        }

        // mqttTemplate.convertAndSend(topic, message);
    }

    /**
     * 统计学校设备概况
     */
    public DeviceOverview getSchoolDeviceOverview(String schoolId) {
        DeviceOverview overview = new DeviceOverview();
        // 各类型设备数量统计
        // overview.setTotalPens(deviceRepository.countBySchoolAndType(schoolId, "pen"));
        // overview.setTotalGateways(deviceRepository.countBySchoolAndType(schoolId, "gateway"));
        // overview.setOnlinePens(countOnlineDevices(schoolId, "pen"));
        // overview.setOnlineGateways(countOnlineDevices(schoolId, "gateway"));
        return overview;
    }

    // ==================== 内部方法 ====================

    /** 更新Redis中设备在线状态 */
    private void updateDeviceOnlineStatus(String deviceId, boolean online) {
        String key = "writech:device:online:" + deviceId;
        if (online) {
            redisTemplate.opsForValue().set(key, "1", 
                    DEVICE_ONLINE_TIMEOUT, java.util.concurrent.TimeUnit.SECONDS);
        } else {
            redisTemplate.delete(key);
        }
    }

    // ==================== 内部类 ====================

    /** 设备概况统计 */
    public static class DeviceOverview {
        private int totalPens;
        private int totalGateways;
        private int totalEdgeBoxes;
        private int totalTerminals;
        private int onlinePens;
        private int onlineGateways;
        private int onlineEdgeBoxes;
        private double averageBatteryLevel;

        public int getTotalPens() { return totalPens; }
        public void setTotalPens(int c) { this.totalPens = c; }
        public int getTotalGateways() { return totalGateways; }
        public void setTotalGateways(int c) { this.totalGateways = c; }
        public int getTotalEdgeBoxes() { return totalEdgeBoxes; }
        public void setTotalEdgeBoxes(int c) { this.totalEdgeBoxes = c; }
        public int getTotalTerminals() { return totalTerminals; }
        public void setTotalTerminals(int c) { this.totalTerminals = c; }
        public int getOnlinePens() { return onlinePens; }
        public void setOnlinePens(int c) { this.onlinePens = c; }
        public int getOnlineGateways() { return onlineGateways; }
        public void setOnlineGateways(int c) { this.onlineGateways = c; }
        public int getOnlineEdgeBoxes() { return onlineEdgeBoxes; }
        public void setOnlineEdgeBoxes(int c) { this.onlineEdgeBoxes = c; }
        public double getAverageBatteryLevel() { return averageBatteryLevel; }
        public void setAverageBatteryLevel(double l) { this.averageBatteryLevel = l; }
    }
}
