package com.shzg.project.worn.sensor.mqtt.handler;

import com.alibaba.fastjson2.JSONObject;
import com.shzg.project.system.domain.SysDept;
import com.shzg.project.system.service.ISysDeptService;
import com.shzg.project.worn.domain.MqttSensorDevice;
import com.shzg.project.worn.domain.MqttSensorData;
import com.shzg.project.worn.domain.MqttSensorEvent;
import com.shzg.project.worn.service.IDeviceStatusService;
import com.shzg.project.worn.service.IMqttSensorDataService;
import com.shzg.project.worn.service.IMqttSensorEventService;
import com.shzg.project.worn.unit.DeviceStatusUtil;
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Base64;
import java.util.Date;

@Slf4j
@Component
public class WaterSensorHandler {

    @Autowired
    private IMqttSensorDataService sensorDataService;

    @Autowired
    private IMqttSensorEventService eventService;

    @Autowired
    private WebSocketSessionManager sessionManager;

    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private IDeviceStatusService deviceStatusService;

    @Autowired
    private DeviceStatusUtil deviceStatusUtil;

    public void handle(MqttSensorDevice device, String topic, String payload) {

        if (device == null) return;
        if (device.getDeptId() == null) return;

        JSONObject json = parseJson(payload);
        if (json == null) return;

        WaterInfo info = parsePayload(json);
        if (info == null) return;

        TopicInfo topicInfo = parseTopic(topic);

        // ================== 查询部门 ==================
        String deptName = null;
        SysDept dept = deptService.selectDeptById(device.getDeptId());
        if (dept != null) {
            deptName = dept.getDeptName();
        }

        // ================== 入库 ==================
        saveData(device, topic, payload, topicInfo, info);

        // ================== 恢复在线 ==================
        deviceStatusUtil.handleOnline(device);

        // ================== 状态计算 ==================
        String status = (info.getWater() != null && info.getWater() == 1)
                ? "alarm"
                : "normal";

        // ================== WebSocket ==================
        pushWebSocket(device, deptName, info, status);

        // ================== Redis去重 ==================
        boolean changed = deviceStatusService.isStatusChanged(
                device.getId(),
                "water",
                status
        );

        if (!changed) {
            return;
        }

        // ================== 事件处理 ==================
        if ("alarm".equals(status)) {
            triggerEvent(device, "alarm", "HIGH", "浸水预警！", deptName);
        } else {
            triggerEvent(device, "recovery", "LOW", "水浸正常", deptName);
        }

        log.info("[WATER] 状态变化 deviceId={}, status={}", device.getId(), status);
    }

    // ================== WebSocket ==================
    private void pushWebSocket(MqttSensorDevice device,
                               String deptName,
                               WaterInfo info,
                               String status) {

        JSONObject msg = new JSONObject();

        msg.put("type", "water");
        msg.put("deviceId", device.getId());
        msg.put("deviceName", device.getDeviceName());
        msg.put("deptId", device.getDeptId());
        msg.put("deptName", deptName);

        msg.put("battery", info.getBattery());
        msg.put("water", info.getWater());
        msg.put("status", status);
        msg.put("time", System.currentTimeMillis());

        sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
    }

    // ================== 事件 ==================
    private void triggerEvent(MqttSensorDevice device,
                              String type,
                              String level,
                              String desc,
                              String deptName) {

        MqttSensorEvent event = new MqttSensorEvent();
        event.setDeviceId(device.getId());
        event.setDeptId(device.getDeptId());
        event.setEventType(type);
        event.setLevel(level);
        event.setEventDesc(desc);
        event.setStatus("0");
        event.setIsDelete("0");
        event.setCreateTime(new Date());

        eventService.insertMqttSensorEvent(event);

        JSONObject msg = new JSONObject();
        msg.put("type", "alarm");
        msg.put("deviceId", device.getId());
        msg.put("deviceName", device.getDeviceName());
        msg.put("deptId", device.getDeptId());
        msg.put("deptName", deptName);

        msg.put("eventType", type);
        msg.put("level", level);
        msg.put("eventDesc", desc);
        msg.put("time", System.currentTimeMillis());

        sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
    }

    // ================== 入库 ==================
    private void saveData(MqttSensorDevice device,
                          String topic,
                          String payload,
                          TopicInfo topicInfo,
                          WaterInfo info) {

        MqttSensorData data = new MqttSensorData();
        data.setDeviceId(device.getId());
        data.setDeptId(device.getDeptId());
        data.setTopic(topic);
        data.setProject(topicInfo.project);
        data.setWarehouse(topicInfo.warehouse);
        data.setPayload(payload);
        data.setDataJson(payload);

        data.setWaterStatus(info.getWater());
        data.setBattery(info.getBattery() == null ? null : info.getBattery().longValue());

        data.setCreateTime(new Date());
        data.setIsDelete("0");

        sensorDataService.insertMqttSensorData(data);
    }

    // ================== 工具 ==================
    private JSONObject parseJson(String payload) {
        try {
            return JSONObject.parseObject(payload);
        } catch (Exception e) {
            return null;
        }
    }

    private TopicInfo parseTopic(String topic) {
        TopicInfo info = new TopicInfo();
        try {
            String[] arr = topic.split("/");
            info.project = arr.length > 1 ? arr[1] : "";
            info.warehouse = arr.length > 2 ? arr[2] : "";
        } catch (Exception ignored) {}
        return info;
    }

    private WaterInfo parsePayload(JSONObject json) {

        try {
            String data = json.getString("data");
            if (data == null) return null;

            byte[] bytes = Base64.getDecoder().decode(data);
            WaterInfo result = new WaterInfo();

            for (int i = 0; i < bytes.length - 2; ) {

                int cid = bytes[i] & 0xFF;
                int type = bytes[i + 1] & 0xFF;

                if (cid == 0x01 && type == 0x75) {
                    result.setBattery(bytes[i + 2] & 0xFF);
                    i += 3;
                    continue;
                }

                if (cid == 0x05 && type == 0x00) {
                    result.setWater(bytes[i + 2] & 0xFF);
                    i += 3;
                    continue;
                }

                i++;
            }

            return result;

        } catch (Exception e) {
            return null;
        }
    }

    private static class TopicInfo {
        String project;
        String warehouse;
    }

    private static class WaterInfo {
        private Integer battery;
        private Integer water;

        public Integer getBattery() { return battery; }
        public void setBattery(Integer battery) { this.battery = battery; }

        public Integer getWater() { return water; }
        public void setWater(Integer water) { this.water = water; }
    }
}