package com.kuyuntech.vrv.platform.configuration.core;

import com.alibaba.fastjson.JSONObject;
import com.kuyuntech.vrv.coreapi.bean.core.DeviceParamBean;
import com.kuyuntech.vrv.coreapi.service.core.DeviceParamService;
import com.kuyuntech.vrv.platform.readJson.Test;
import com.kuyuntech.vrv.platform.util.core.CompareParamValue;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class MqttConfiguration {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DeviceParamService deviceParamService;

    // 消费消息

    /**
     * 创建MqttPahoClientFactory，设置MQTT Broker连接属性，如果使用SSL验证，也在这里设置。
     *
     * @return factory
     */
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        MqttConnectOptions options = new MqttConnectOptions();

        // 设置代理端的URL地址，可以是多个
        options.setServerURIs(new String[]{"tcp://47.107.255.78:1883"});

        factory.setConnectionOptions(options);
        return factory;
    }

    /**
     * 入站通道
     */
    @Bean
    public MessageChannel mqttInputChannel() {
        return new DirectChannel();
    }

    /**
     * 入站
     */
    @Bean
    public MessageProducer inbound() {
        // Paho客户端消息驱动通道适配器，主要用来订阅主题
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter("consumerClient-paho",
                mqttClientFactory(), "mqtt/335102012203A500/data", "mqtt/335102012203A500/cmd", "battery", "+/sensor");
        adapter.setCompletionTimeout(5000);

        // Paho消息转换器
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
        // 按字节接收消息
//        defaultPahoMessageConverter.setPayloadAsBytes(true);
        adapter.setConverter(defaultPahoMessageConverter);
        adapter.setQos(1); // 设置QoS
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }

    @Bean
    // ServiceActivator注解表明：当前方法用于处理MQTT消息，inputChannel参数指定了用于消费消息的channel。
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public MessageHandler handler() {
        return message -> {

            String payload = message.getPayload().toString();

            // byte[] bytes = (byte[]) message.getPayload(); // 收到的消息是字节格式
            String topic = message.getHeaders().get("mqtt_receivedTopic").toString();

            // 根据主题分别进行消息处理。
            if (topic.matches(".+/sensor")) { // 匹配：1/sensor
                String sensorSn = topic.split("/")[0];
                System.out.println("传感器" + sensorSn + ": 的消息： " + payload);
            } else if (topic.equals("collector")) {
                System.out.println("采集器的消息：" + payload);
            } else {
                System.out.println("丢弃消息：主题[" + topic + "]，负载：" + payload);

                //String转Json
                JSONObject jsonObject = JSONObject.parseObject(payload);

                String devices = jsonObject.getString("devices");

                //取里面
                List<Test> list = JSONObject.parseArray(devices, Test.class);

                //CK1
                String deviceId = list.get(0).getDeviceId();
                //CK2
                String deviceId2 = list.get(1).getDeviceId();

                //取deviceData
                HashMap<String, String> deviceData = list.get(0).getDeviceData();
                //CK2的deviceData
                HashMap<String, String> deviceData2 = list.get(1).getDeviceData();

                //存入数据库的新增方法,将第一次读取到的数据存入数据库


                //先将数据存入redis，检验所有数据，如果出现数据改变，就执行update更新数据库，并更新redis

                //用长度做判断
                Long size = redisTemplate.opsForHash().size("paramKeyValue");
                Long size2 = redisTemplate.opsForHash().size("paramKeyValueCK2");
                System.out.println(size);
                System.out.println(size2);

                if (size == 0) {
                    //遍历CK1数据
                    for (Map.Entry<String, String> entry : deviceData.entrySet()) {

                        String name = entry.getKey();
                        String value = entry.getValue();

                        //存入hash
                        redisTemplate.opsForHash().put("paramKeyValue", name, value);

                        System.out.println("CK1存入redis成功！");
                    }
                }

                if (size2 == 0) {
                    //遍历CK2数据
                    for (Map.Entry<String, String> entry : deviceData2.entrySet()) {

                        String name = entry.getKey();
                        String value = entry.getValue();

                        //存入hash
                        redisTemplate.opsForHash().put("paramKeyValueCK2", name, value);

                        System.out.println("CK2存入redis成功！");
                    }
                }

                //遍历redis中hash的每一个键值对和mqtt传过来的数据进行比较

                //获取paramKeyValue键值对
                HashMap<String, String> paramKeyValue = (HashMap<String, String>) redisTemplate.opsForHash().entries("paramKeyValue");
                HashMap<String, String> paramKeyValueCK2 = (HashMap<String, String>) redisTemplate.opsForHash().entries("paramKeyValueCK2");

                System.out.println("----------------------------");
                System.out.println(deviceData);
                System.out.println(paramKeyValue);
                System.out.println("----------------------------");
                System.out.println(deviceData2);
                System.out.println(paramKeyValueCK2);
                System.out.println("----------------------------");

                boolean result = CompareParamValue.CompareParamValue(paramKeyValue, deviceData);
                boolean result2 = CompareParamValue.CompareParamValue(paramKeyValueCK2, deviceData2);

                System.out.println("CK1比较的结果：" + result);
                System.out.println("CK2比较的结果：" + result2);

                //如果不相等，清除缓存，重新加入，并更新数据库
                if (result == false) {
                    //清除redis缓存
                    redisTemplate.delete("paramKeyValue");

                    //重新存入redis
                    for (Map.Entry<String, String> entry : deviceData.entrySet()) {

                        String name = entry.getKey();
                        String value = entry.getValue();

                        //存入hash
                        redisTemplate.opsForHash().put("paramKeyValue", name, value);

                        System.out.println("重新存入redis成功！");
                    }

                    long id = 199;

                    //更新数据库
                    for (Map.Entry<String, String> entry : deviceData.entrySet()) {
                        DeviceParamBean deviceParamBean = new DeviceParamBean();

                        deviceParamBean.setSn(deviceId);

                        String name = entry.getKey();
                        String value = entry.getValue();


                        deviceParamBean.setId(id);

                        id = id + 1;

                        deviceParamBean.setName(name);
                        deviceParamBean.setValue(value);

                        deviceParamBean = this.deviceParamService.updateParam(deviceParamBean);

                        System.out.println("id为：" + id + "-- 更新后的数据：" + deviceParamBean);

                    }
                }

                //如果不相等，清除缓存，重新加入，并更新数据库
                if (result2 == false) {
                    //清除redis缓存
                    redisTemplate.delete("paramKeyValueCK2");

                    //重新存入redis
                    for (Map.Entry<String, String> entry : deviceData2.entrySet()) {

                        String name = entry.getKey();
                        String value = entry.getValue();

                        //存入hash
                        redisTemplate.opsForHash().put("paramKeyValueCK2", name, value);

                        System.out.println("重新存入redis成功！");
                    }

                    //更新数据库
                    for (Map.Entry<String, String> entry : deviceData2.entrySet()) {
                        DeviceParamBean deviceParamBean = new DeviceParamBean();
                        deviceParamBean.setSn(deviceId2);

                        for (long i = 298; i < 300; i++) {
                            deviceParamBean.setId(i);
                        }

                        String name = entry.getKey();
                        String value = entry.getValue();

                        deviceParamBean.setName(name);
                        deviceParamBean.setValue(value);

                        deviceParamBean = this.deviceParamService.updateParam(deviceParamBean);
                    }
                }
            }

        };
    }

    // 发送消息

    /**
     * 出站通道
     */
    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }

    /**
     * 出站
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttOutboundChannel")
    public MessageHandler outbound() {

        // 发送消息和消费消息Channel可以使用相同MqttPahoClientFactory
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler("publishClient", mqttClientFactory());
        messageHandler.setAsync(true); // 如果设置成true，即异步，发送消息时将不会阻塞。
        messageHandler.setDefaultTopic("command");
        messageHandler.setDefaultQos(1); // 设置默认QoS

        // Paho消息转换器
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();

        // defaultPahoMessageConverter.setPayloadAsBytes(true); // 发送默认按字节类型发送消息
        messageHandler.setConverter(defaultPahoMessageConverter);
        return messageHandler;
    }

}
