package com.fuyuanshen.global.mqtt.receiver;

import cn.hutool.core.lang.Dict;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.json.utils.JsonUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.global.mqtt.base.*;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;

@Service
@Slf4j
public class ReceiverMessageHandler implements MessageHandler {

    @Autowired
    private MqttRuleEngine ruleEngine;

    @Autowired
    private NewMqttRuleEngine newRuleEngine;

    @Override
    public void handleMessage(Message<?> message) throws MessagingException {
        Object payload = message.getPayload();
        MessageHeaders headers = message.getHeaders();
        String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
        String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString();
        String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString();

        log.info("MQTT payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}",
                payload, receivedTopic, receivedQos, timestamp);

        Dict payloadDict = JsonUtils.parseMap(payload.toString());
        if (receivedTopic == null || payloadDict == null) {
            return;
        }

        // 模版格式匹配
        boolean flag = checkTemplateFormatMatching(payloadDict);


        String[] subStr = receivedTopic.split("/");
        String deviceImei = null;
        if(flag){
            deviceImei = payloadDict.getStr("imei");
        } else {
            deviceImei = subStr[1];
        }

        RedissonClient client = RedisUtils.getClient();
        String lockKey = "mqtt:consumer:lock:";
        String  KEY = GlobalConstants.GLOBAL_REDIS_KEY + lockKey + deviceImei;
        RLock lock = client.getLock(KEY);

        try {
            // 尝试获取锁，
            boolean isLocked = lock.tryLock(60, 3000, TimeUnit.MILLISECONDS);
            if (isLocked) {
                String state = payloadDict.getStr("state");
                Object[] convertArr = ImageToCArrayConverter.convertByteStringToMixedObjectArray(state);
                if(StringUtils.isNotBlank(deviceImei)){
                    String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
                    String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
                    RedisUtils.offerDeduplicated(queueKey,dedupKey,deviceImei, Duration.ofSeconds(900));
                    //在线状态
                    String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
                    RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
                }

                // 新的通信协议
                if(flag){
                    String[] topicArr = receivedTopic.split("/");
                    String funcType = payloadDict.getStr("funcType");
                    NewMqttRuleContext context = new NewMqttRuleContext();
                    context.setCommandType(topicArr[2]+"_"+funcType);
                    context.setDeviceImei(deviceImei);
                    context.setPayloadDict(payloadDict);

                    boolean ruleExecuted = newRuleEngine.executeRule(context);

                    if (!ruleExecuted) {
                        log.warn("未找到匹配的规则来处理命令类型: {}", topicArr[2] + " : " +funcType);
                    }
                    return;
                }

                if (convertArr.length > 0) {
                    Byte val1 = (Byte) convertArr[0];
                    MqttRuleContext context = new MqttRuleContext();
                    context.setCommandType(val1);
                    context.setConvertArr(convertArr);
                    context.setDeviceImei(deviceImei);
                    context.setPayloadDict(payloadDict);

                    boolean ruleExecuted = ruleEngine.executeRule(context);

                    if (!ruleExecuted) {
                        log.warn("未找到匹配的规则来处理命令类型: {}", val1);
                    }
                    return;
                }

                /* ===== 追加：根据报文内容识别格式并统一解析 ===== */
                int intType = MqttXinghanCommandType.computeVirtualCommandType(payloadDict);
                if (intType > 0) {
                    MqttRuleContext newCtx = new MqttRuleContext();
                    newCtx.setCommandType((byte) intType);
                    newCtx.setDeviceImei(deviceImei);
                    newCtx.setPayloadDict(payloadDict);

                    boolean ok = ruleEngine.executeRule(newCtx);
                    if (!ok) {
                        log.warn("新规则引擎未命中, imei={}", deviceImei);
                    }
                }
            }else{
                log.warn("MQTT获取锁失败，请稍后再试");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private boolean checkTemplateFormatMatching(Dict payloadDict) {
        // 检查是否包含指定的 key
        boolean hasImei = payloadDict.containsKey("imei");
        boolean hasFuncType = payloadDict.containsKey("funcType");
        boolean hasStatus = payloadDict.containsKey("status");
        boolean hasTimestamp = payloadDict.containsKey("timestamp");
        boolean hasData = payloadDict.containsKey("data");

        // 输出检查结果
        log.info("包含 imei: {}, funcType: {}, status: {}, timestamp: {}, data: {}",
                hasImei, hasFuncType, hasStatus, hasTimestamp, hasData);
        return hasImei && hasFuncType && hasStatus && hasTimestamp && hasData;
    }

}
