package com.fuyuanshen.global.mqtt.rule.xinghan;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fuyuanshen.common.json.utils.JsonUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
import com.fuyuanshen.global.mqtt.config.MqttGateway;
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
import com.fuyuanshen.global.mqtt.constants.XingHanCommandTypeConstants;
import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.time.Duration;
import java.util.*;

import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;

/**
 * 星汉设备发送消息 下发规则：
 * <p>
 * 1. 设备上行 sta_TexTarns=genius!  => 仅标记成功<br>
 * 2. 设备上行 sta_TexTarns=数字   => GBK编码，每行文字为一包，一共4包，第一字节为包序号
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class XinghanSendMsgRule implements MqttMessageRule {

    private final MqttGateway mqttGateway;
    private final ObjectMapper objectMapper;

    @Override
    public String getCommandType() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

        // 三种等价的写法
        Integer[] array1 = list.toArray(new Integer[0]);
        Integer[] array2 = list.toArray(size -> new Integer[size]);

        return XingHanCommandTypeConstants.XingHan_ESEND_MSG;
    }

    @Override
    public void execute(MqttRuleContext ctx) {
        String functionAccess = FUNCTION_ACCESS_KEY + "MSG:" + ctx.getDeviceImei();
        try {
            XinghanSendMsgRule.MqttXinghanMsgJson payload = objectMapper.convertValue(
                    ctx.getPayloadDict(), XinghanSendMsgRule.MqttXinghanMsgJson.class);

            String respText = payload.getStaTexTrans();
            log.info("设备上报人员信息： {} ", respText);

            // --- 去重 START ---
            String dedupKey = "xd:MSG:dedup:" + ctx.getDeviceImei() + ":" + respText;
            boolean first = RedisUtils.setObjectIfAbsent(dedupKey, "1", Duration.ofSeconds(3));
            if (!first) {
                log.warn("重复消息丢弃 {}", dedupKey);
                return;
            }

            // 1. genius! —— 成功标记
            if ("genius!".equalsIgnoreCase(respText)) {
                RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
                log.info("设备 {} 发送消息完成", ctx.getDeviceImei());
                return;
            }
            // 2. 数字 —— 下发数据块
            int blockIndex;
            try {
                blockIndex = Integer.parseInt(respText);
            } catch (NumberFormatException ex) {
                log.warn("设备 {} 消息上报非法块号：{}", ctx.getDeviceImei(), respText);
                return;
            }
            // 将发送的信息原文本以List<String>形式存储在Redis中
            List<String> data = RedisUtils.getCacheList(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + ctx.getDeviceImei() + ":app_send_message_data");
            if (data.isEmpty()) {
                return;
            }
            //
            ArrayList<Integer> intData = new ArrayList<>();
            intData.add(blockIndex);
            // 获取块原内容 转成GBK  再转成无符号十进制整数
            String blockTxt = data.get(blockIndex-1);
            log.warn("设备上报人员登记信息：{}", blockTxt);
            // 再按 GBK 编码把字符串转成字节数组，并逐个转为无符号十进制整数
            for (byte b : blockTxt.getBytes(GBK)) {
                intData.add(b & 0xFF);   // b & 0xFF 得到 0~255 的整数
            }

            Map<String, Object> map = new HashMap<>();
            map.put("ins_TexTrans", intData);

            String topic = MqttConstants.GLOBAL_PUB_KEY + ctx.getDeviceImei();
            String json = JsonUtils.toJsonString(map);
            mqttGateway.sendMsgToMqtt(topic, 1, json);
            log.info("发送设备信息数据到设备消息=>topic:{},payload:{}",
                    MqttConstants.GLOBAL_PUB_KEY + ctx.getDeviceImei(),
                    JsonUtils.toJsonString(map));

        } catch (Exception e) {
            log.error("处理发送设备信息时出错", e);
            RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
        }
    }

    private static final Charset GBK = Charset.forName("GBK");

    /* ---------- DTO ---------- */

    @Data
    private static class MqttXinghanMsgJson {
        /**
         * 设备上行：
         * 数字  -> 请求对应块号
         * genius! -> 写入成功
         */
        @JsonProperty("sta_TexTrans")
        private String staTexTrans;
    }
}
