/**
 * 自然写互动课堂教学管理云平台软件 V1.0
 * 
 * 设备管理控制器
 * 负责点阵笔、网关、终端设备的注册、绑定、状态查询等接口
 */
package com.writech.cloud.controller;

import com.writech.cloud.WritechCloudApplication.ApiResponse;
import com.writech.cloud.WritechCloudApplication.BusinessException;
import com.writech.cloud.model.Device;
import com.writech.cloud.service.DeviceService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 设备控制器 - /api/v1/device
 * 
 * 管理互动课堂中涉及的所有智能硬件设备：
 * - 点阵笔（pen）：学生书写工具，通过BLE连接网关
 * - 网关设备（gateway）：教室中枢，管理多支笔的连接与数据转发
 * - 终端设备（terminal）：黑板、PC、电视、平板等显示终端
 * - 算力盒（edge_box）：教室端AI推理设备
 */
@RestController
@RequestMapping("/api/v1/device")
public class DeviceController {

    @Autowired
    private DeviceService deviceService;

    /**
     * 设备注册接口
     * POST /api/v1/device/register
     * 
     * 将新设备注册到云平台，绑定至指定用户和学校
     * 注册时校验设备MAC地址唯一性和设备证书有效性
     * 
     * @param request 注册请求（MAC地址、设备类型、序列号等）
     * @return 注册成功后的设备信息
     */
    @PostMapping("/register")
    public ApiResponse<DeviceRegisterResponse> registerDevice(
            @Valid @RequestBody DeviceRegisterRequest request) {
        
        // 校验设备MAC地址格式
        if (!isValidMacAddress(request.getMacAddr())) {
            throw new BusinessException(400, "无效的MAC地址格式");
        }

        // 检查设备是否已注册
        Device existing = deviceService.findByMacAddr(request.getMacAddr());
        if (existing != null) {
            throw new BusinessException(409, "设备已注册，MAC地址: " + request.getMacAddr());
        }

        // 校验设备证书（X.509）
        boolean certValid = deviceService.validateDeviceCertificate(
                request.getMacAddr(), request.getDeviceCert());
        if (!certValid) {
            throw new BusinessException(403, "设备证书校验失败，拒绝注册");
        }

        // 创建设备记录
        Device device = new Device();
        device.setId(UUID.randomUUID().toString().replace("-", ""));
        device.setType(request.getDeviceType());
        device.setMacAddr(request.getMacAddr());
        device.setSerialNumber(request.getSerialNumber());
        device.setFirmwareVersion(request.getFirmwareVersion());
        device.setBindUserId(request.getUserId());
        device.setSchoolId(request.getSchoolId());
        device.setClassroomId(request.getClassroomId());
        device.setStatus(1); // 1=在线
        device.setRegisterTime(LocalDateTime.now());
        device.setLastHeartbeat(LocalDateTime.now());

        deviceService.save(device);

        // 返回注册结果
        DeviceRegisterResponse response = new DeviceRegisterResponse();
        response.setDeviceId(device.getId());
        response.setMacAddr(device.getMacAddr());
        response.setDeviceType(device.getType());
        response.setRegisteredAt(device.getRegisterTime());

        return ApiResponse.success(response);
    }

    /**
     * 设备绑定接口
     * POST /api/v1/device/bind
     * 
     * 将已注册设备绑定至指定用户（教师/学生）
     * 一支笔只能绑定一个用户，一个用户可绑定多支笔
     */
    @PostMapping("/bind")
    public ApiResponse<Void> bindDevice(@Valid @RequestBody DeviceBindRequest request) {
        Device device = deviceService.findById(request.getDeviceId());
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }

        // 检查笔是否已被其他用户绑定
        if ("pen".equals(device.getType()) && device.getBindUserId() != null
                && !device.getBindUserId().equals(request.getUserId())) {
            throw new BusinessException(409, "该笔已绑定其他用户，请先解绑");
        }

        deviceService.bindDevice(request.getDeviceId(), request.getUserId(),
                request.getClassroomId());
        return ApiResponse.success();
    }

    /**
     * 设备解绑接口
     * POST /api/v1/device/unbind
     */
    @PostMapping("/unbind")
    public ApiResponse<Void> unbindDevice(@RequestBody DeviceUnbindRequest request) {
        deviceService.unbindDevice(request.getDeviceId());
        return ApiResponse.success();
    }

    /**
     * 查询设备列表
     * GET /api/v1/device/list
     * 
     * 按学校/教室/设备类型/状态等条件分页查询设备
     */
    @GetMapping("/list")
    public ApiResponse<Page<Device>> listDevices(
            @RequestParam(required = false) String schoolId,
            @RequestParam(required = false) String classroomId,
            @RequestParam(required = false) String deviceType,
            @RequestParam(required = false) Integer status,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size) {
        
        Page<Device> devices = deviceService.queryDevices(
                schoolId, classroomId, deviceType, status,
                PageRequest.of(page, size));
        return ApiResponse.success(devices);
    }

    /**
     * 查询单个设备详情
     * GET /api/v1/device/{id}
     */
    @GetMapping("/{id}")
    public ApiResponse<DeviceDetailResponse> getDevice(@PathVariable String id) {
        Device device = deviceService.findById(id);
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }

        DeviceDetailResponse detail = new DeviceDetailResponse();
        detail.setDeviceId(device.getId());
        detail.setType(device.getType());
        detail.setMacAddr(device.getMacAddr());
        detail.setSerialNumber(device.getSerialNumber());
        detail.setFirmwareVersion(device.getFirmwareVersion());
        detail.setStatus(device.getStatus());
        detail.setBindUserId(device.getBindUserId());
        detail.setSchoolId(device.getSchoolId());
        detail.setClassroomId(device.getClassroomId());
        detail.setBatteryLevel(device.getBatteryLevel());
        detail.setLastHeartbeat(device.getLastHeartbeat());
        detail.setRegisterTime(device.getRegisterTime());

        return ApiResponse.success(detail);
    }

    /**
     * 设备心跳上报接口
     * POST /api/v1/device/heartbeat
     * 
     * 设备定期上报在线状态、电量、连接笔数等信息
     * 网关设备每30秒上报一次，笔设备每5分钟上报一次
     */
    @PostMapping("/heartbeat")
    public ApiResponse<Void> heartbeat(@Valid @RequestBody HeartbeatRequest request) {
        Device device = deviceService.findById(request.getDeviceId());
        if (device == null) {
            throw new BusinessException(404, "设备不存在");
        }

        // 更新设备状态
        device.setStatus(1); // 在线
        device.setLastHeartbeat(LocalDateTime.now());
        device.setBatteryLevel(request.getBatteryLevel());
        if (request.getConnectedPenCount() != null) {
            device.setConnectedPenCount(request.getConnectedPenCount());
        }
        if (request.getCpuUsage() != null) {
            device.setCpuUsage(request.getCpuUsage());
        }
        if (request.getMemoryUsage() != null) {
            device.setMemoryUsage(request.getMemoryUsage());
        }

        deviceService.updateHeartbeat(device);
        return ApiResponse.success();
    }

    /**
     * 批量查询教室设备拓扑
     * GET /api/v1/device/topology/{classroomId}
     * 
     * 返回指定教室中所有设备的连接拓扑关系
     * 包括网关、笔、算力盒、黑板等设备的层级关系
     */
    @GetMapping("/topology/{classroomId}")
    public ApiResponse<ClassroomTopology> getTopology(@PathVariable String classroomId) {
        ClassroomTopology topology = deviceService.buildClassroomTopology(classroomId);
        return ApiResponse.success(topology);
    }

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

    /** MAC地址格式校验（支持 XX:XX:XX:XX:XX:XX 和 XX-XX-XX-XX-XX-XX） */
    private boolean isValidMacAddress(String mac) {
        if (mac == null) return false;
        return mac.matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$");
    }

    // ==================== DTO 定义 ====================

    /** 设备注册请求 */
    public static class DeviceRegisterRequest {
        @NotBlank(message = "设备类型不能为空")
        private String deviceType;    // pen/gateway/terminal/edge_box
        @NotBlank(message = "MAC地址不能为空")
        private String macAddr;
        private String serialNumber;
        private String firmwareVersion;
        private String userId;
        private String schoolId;
        private String classroomId;
        private String deviceCert;    // X.509设备证书

        public String getDeviceType() { return deviceType; }
        public void setDeviceType(String t) { this.deviceType = t; }
        public String getMacAddr() { return macAddr; }
        public void setMacAddr(String m) { this.macAddr = m; }
        public String getSerialNumber() { return serialNumber; }
        public void setSerialNumber(String s) { this.serialNumber = s; }
        public String getFirmwareVersion() { return firmwareVersion; }
        public void setFirmwareVersion(String v) { this.firmwareVersion = v; }
        public String getUserId() { return userId; }
        public void setUserId(String id) { this.userId = id; }
        public String getSchoolId() { return schoolId; }
        public void setSchoolId(String id) { this.schoolId = id; }
        public String getClassroomId() { return classroomId; }
        public void setClassroomId(String id) { this.classroomId = id; }
        public String getDeviceCert() { return deviceCert; }
        public void setDeviceCert(String c) { this.deviceCert = c; }
    }

    /** 设备注册响应 */
    public static class DeviceRegisterResponse {
        private String deviceId;
        private String macAddr;
        private String deviceType;
        private LocalDateTime registeredAt;

        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String id) { this.deviceId = id; }
        public String getMacAddr() { return macAddr; }
        public void setMacAddr(String m) { this.macAddr = m; }
        public String getDeviceType() { return deviceType; }
        public void setDeviceType(String t) { this.deviceType = t; }
        public LocalDateTime getRegisteredAt() { return registeredAt; }
        public void setRegisteredAt(LocalDateTime t) { this.registeredAt = t; }
    }

    /** 设备绑定请求 */
    public static class DeviceBindRequest {
        @NotBlank private String deviceId;
        @NotBlank private String userId;
        private String classroomId;
        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String id) { this.deviceId = id; }
        public String getUserId() { return userId; }
        public void setUserId(String id) { this.userId = id; }
        public String getClassroomId() { return classroomId; }
        public void setClassroomId(String id) { this.classroomId = id; }
    }

    /** 设备解绑请求 */
    public static class DeviceUnbindRequest {
        private String deviceId;
        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String id) { this.deviceId = id; }
    }

    /** 心跳请求 */
    public static class HeartbeatRequest {
        @NotBlank private String deviceId;
        private Integer batteryLevel;
        private Integer connectedPenCount;
        private Double cpuUsage;
        private Double memoryUsage;

        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String id) { this.deviceId = id; }
        public Integer getBatteryLevel() { return batteryLevel; }
        public void setBatteryLevel(Integer l) { this.batteryLevel = l; }
        public Integer getConnectedPenCount() { return connectedPenCount; }
        public void setConnectedPenCount(Integer c) { this.connectedPenCount = c; }
        public Double getCpuUsage() { return cpuUsage; }
        public void setCpuUsage(Double u) { this.cpuUsage = u; }
        public Double getMemoryUsage() { return memoryUsage; }
        public void setMemoryUsage(Double u) { this.memoryUsage = u; }
    }

    /** 设备详情响应 */
    public static class DeviceDetailResponse {
        private String deviceId;
        private String type;
        private String macAddr;
        private String serialNumber;
        private String firmwareVersion;
        private int status;
        private String bindUserId;
        private String schoolId;
        private String classroomId;
        private Integer batteryLevel;
        private LocalDateTime lastHeartbeat;
        private LocalDateTime registerTime;

        public String getDeviceId() { return deviceId; }
        public void setDeviceId(String id) { this.deviceId = id; }
        public String getType() { return type; }
        public void setType(String t) { this.type = t; }
        public String getMacAddr() { return macAddr; }
        public void setMacAddr(String m) { this.macAddr = m; }
        public String getSerialNumber() { return serialNumber; }
        public void setSerialNumber(String s) { this.serialNumber = s; }
        public String getFirmwareVersion() { return firmwareVersion; }
        public void setFirmwareVersion(String v) { this.firmwareVersion = v; }
        public int getStatus() { return status; }
        public void setStatus(int s) { this.status = s; }
        public String getBindUserId() { return bindUserId; }
        public void setBindUserId(String id) { this.bindUserId = id; }
        public String getSchoolId() { return schoolId; }
        public void setSchoolId(String id) { this.schoolId = id; }
        public String getClassroomId() { return classroomId; }
        public void setClassroomId(String id) { this.classroomId = id; }
        public Integer getBatteryLevel() { return batteryLevel; }
        public void setBatteryLevel(Integer l) { this.batteryLevel = l; }
        public LocalDateTime getLastHeartbeat() { return lastHeartbeat; }
        public void setLastHeartbeat(LocalDateTime t) { this.lastHeartbeat = t; }
        public LocalDateTime getRegisterTime() { return registerTime; }
        public void setRegisterTime(LocalDateTime t) { this.registerTime = t; }
    }

    /** 教室拓扑结构 */
    public static class ClassroomTopology {
        private String classroomId;
        private String classroomName;
        private List<Device> gateways;
        private List<Device> edgeBoxes;
        private List<Device> terminals;
        private List<Device> pens;
        private int totalDeviceCount;

        public String getClassroomId() { return classroomId; }
        public void setClassroomId(String id) { this.classroomId = id; }
        public String getClassroomName() { return classroomName; }
        public void setClassroomName(String n) { this.classroomName = n; }
        public List<Device> getGateways() { return gateways; }
        public void setGateways(List<Device> g) { this.gateways = g; }
        public List<Device> getEdgeBoxes() { return edgeBoxes; }
        public void setEdgeBoxes(List<Device> e) { this.edgeBoxes = e; }
        public List<Device> getTerminals() { return terminals; }
        public void setTerminals(List<Device> t) { this.terminals = t; }
        public List<Device> getPens() { return pens; }
        public void setPens(List<Device> p) { this.pens = p; }
        public int getTotalDeviceCount() { return totalDeviceCount; }
        public void setTotalDeviceCount(int c) { this.totalDeviceCount = c; }
    }
}
