package com.yuchen.saas.park.service.iot;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yuchen.saas.device.api.feign.DeviceSceneLinkageRuleClient;
import com.yuchen.saas.device.api.feign.NetAlarmFeign;
import com.yuchen.saas.device.api.vo.RunDeviceSceneLinkageRuleVo;
import com.yuchen.saas.park.api.dto.park.IoTEvent;
import com.yuchen.saas.park.api.entity.fault.ConnectEvent;
import com.yuchen.saas.park.api.vo.fault.DeviceProperty;
import com.yuchen.saas.park.service.iot.input.ParkDeviceOnlineInput;
import com.yuchen.saas.park.service.iot.input.ParkDevicePropertyInput;
import com.yuchen.saas.park.service.iot.service.SaasParkDeviceMqttService;
import com.yuchen.saas.park.service.service.elevator.ISaasParkElevatorManageLocationService;
import com.yuchen.saas.park.service.service.elevator.ISaasParkElevatorMonitorRunningStateService;
import com.yuchen.saas.park.service.service.elevator.ISaasParkElevatorRecordInoutRecordsService;
import com.yuchen.saas.park.service.service.pldoor.PlDoorInoutRecodeService;
import com.yuchen.saas.park.service.util.SignUtils;
import com.yuchen.saas.park.service.util.TextHelper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Slf4j
@Service
public class NetIotMqttClient {
    @Resource
    private IotMqttConfig iotMqttConfig;
    @Resource
    private ApplicationContext applicationContext;
    private MqttAsyncClient mqttAsyncClient = null;
    @Resource
    private PlDoorInoutRecodeService plDoorInoutRecodeService;
    @Resource
    private  ISaasParkElevatorMonitorRunningStateService iSaasParkElevatorMonitorService;

    @Resource
    private  ISaasParkElevatorRecordInoutRecordsService iSaasParkElevatorRecordInoutRecordsService;

    @Resource
    private SaasParkDeviceMqttService saasParkDeviceMqttService;

    @Resource
    private DeviceSceneLinkageRuleClient deviceSceneLinkageRuleClient;
    @Resource
    private NetAlarmFeign netAlarmFeign;
    @Resource
    private ISaasParkElevatorManageLocationService iSaasParkElevatorManageLocationService;

    @Resource
    private ParkDevicePropertyInput parkDevicePropertyInput;

    @Resource
    private ParkDeviceOnlineInput parkDeviceOnlineInput;


    @PostConstruct
    public void init() {
        try {
            log.info("NetIotMqttClientInitIotMqttConfig = {}", iotMqttConfig.toString());
            long timestamp = System.currentTimeMillis() / 1000L;
            String clientId = "app_" + iotMqttConfig.getAccessKey() + "_" + IdUtil.fastSimpleUUID();
            String userNameStr = clientId + "|" + TextHelper.getRandomString() + "|" + timestamp;
            String password = new String(SignUtils.getSignature(userNameStr, iotMqttConfig.getAccessSecret()).toCharArray());
            log.info("NetIotMqttClientInitClientId={},userNameStr={},password={}", clientId, userNameStr, password);
            // 配置 mqtt 连接配置
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setUserName(userNameStr);
            connOpts.setPassword(password.toCharArray());
            connOpts.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
            connOpts.setMaxInflight(30);
            connOpts.setAutomaticReconnect(true);
            connOpts.setCleanSession(true);
            connOpts.setKeepAliveInterval(60);
            // 声明 mqtt 异步连接
            mqttAsyncClient = new MqttAsyncClient(iotMqttConfig.getUri(), clientId, new MqttDefaultFilePersistence());
            // 声明 mqtt 事件
            setCallback();
            // 连接 mqtt 服务
            connect(connOpts);
        } catch (Exception e) {
            log.error("NetIotMqttClientInitError", e);
        }
    }

    private void setCallback() {
        mqttAsyncClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                subscribe();
            }

            /**
             * 连接丢失
             * @param throwable
             */
            @SneakyThrows
            @Override
            public void connectionLost(Throwable throwable) {
                mqttAsyncClient.connect();
            }

            /**
             * 收到消息
             * @param s 订阅的 Topic
             * @param mqttMessage 消息数据
             * @throws Exception
             */
            @Override
            public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
                log.info("NetIotMqttClientMessageArrived s={}, payload={}", s, new String(mqttMessage.getPayload()));
                try {
                    // 获取 Payload
                    JSONObject jsonObjectPayload = JSONObject.parseObject(new String(mqttMessage.getPayload()));
                    // 获取 Payload 中的 content
                    JSONObject jsonObjectContent = jsonObjectPayload.getJSONObject("content");
                    // 获取 Payload 中的 type
                    String payloadType = jsonObjectPayload.getString("type");
                    // 根据 订阅的 Topic 来处理 对应的数据
                    switch (payloadType) {
                        case "event":
                            // 收到事件数据
                            IoTEvent ioTEvent = JSON.parseObject(jsonObjectContent.toJSONString(), IoTEvent.class);
                            log.info("NetIotMqttClientMessageArrivedEvent , jsonObjectContent = {}",jsonObjectContent.toJSONString());
                            //发送ws
                            iSaasParkElevatorManageLocationService.receiveIotEventInfo(ioTEvent);
                            // 处理设备
                            saasParkDeviceMqttService.receiveIotEvent(ioTEvent.getProductKey(), jsonObjectContent.toJSONString());
//                          // 处理设备事件-门禁进出记录
                            plDoorInoutRecodeService.receiveIotEvent(jsonObjectContent.toJSONString());
//                            //梯控设备状态
                            iSaasParkElevatorMonitorService.receiveIotEvent(jsonObjectContent.toJSONString());
//                            //梯控进出状态
                            iSaasParkElevatorRecordInoutRecordsService.receiveIotEvent(jsonObjectContent.toJSONString());
                            // 告警
                            netAlarmFeign.eventAlarm(ioTEvent);
                            // 触发场景联动
                            deviceSceneLinkageRuleClient.eventRunRule(new RunDeviceSceneLinkageRuleVo(jsonObjectContent.toJSONString()));
                            break;
                        case "property":
                            // 收到属性事件数据
                            DeviceProperty deviceProperty = JSON.parseObject(jsonObjectContent.toJSONString(),DeviceProperty.class);
                            log.info("NetIotMqttClientMessageArrivedProperty , jsonObjectContent = {}",jsonObjectContent.toJSONString());
                            // 存储设备属性值
                            parkDevicePropertyInput.inputData(deviceProperty);
                            // 告警
                            netAlarmFeign.propertyAlarm(deviceProperty);
                            // 触发场景联动
                            deviceSceneLinkageRuleClient.propertyRunRule(new RunDeviceSceneLinkageRuleVo(jsonObjectContent.toJSONString()));
                            break;
                        case "connect":
                        case "disconnect":
                            // 收到断开连接事件数据
                            ConnectEvent connectEvent = JSON.parseObject(jsonObjectContent.toJSONString(), ConnectEvent.class);
                            connectEvent.setOnline("connect".equals(payloadType));
                            log.info("NetIotMqttClientMessageArrivedConnectOrDisconnect , jsonObjectContent = {}",jsonObjectContent.toJSONString());
                            // 存储设备上下线状态
                            parkDeviceOnlineInput.inputData(connectEvent);
                            // 告警
                            netAlarmFeign.connectAlarm(connectEvent);
                            // 触发场景联动
                            deviceSceneLinkageRuleClient.deviceStatusChangeRunRule(new RunDeviceSceneLinkageRuleVo(jsonObjectContent.toJSONString()));
                            //applicationContext.publishEvent(new ReceiveConnectDataEvent(connectEvent));
                            break;
                        default:
                            // 默认还未找到匹配的数据
                    }
                } catch (Exception e) {
                    log.info("NetIotMqttClientMessageArrivedError1", e);
                }

            }

            /**
             * 交付完成
             * @param iMqttDeliveryToken
             */
            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

            }

        });

    }


    private void connect(MqttConnectOptions connOpts) {
        try {
            mqttAsyncClient.connect(connOpts, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    log.info("NetIotMqttClientConnect onSuccess");
                }
                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    log.info("NetIotMqttClientConnect onFailure exception = {}", exception.toString());
                }
            });
            log.info("NetIotMqttClientConnect serverUrl = {}", iotMqttConfig.getUri());
        } catch (Exception e) {
            log.info("NetIotMqttClientConnect error", e);
        }
    }

    private void subscribe() {
        for (String product : NetParkProductEnum.productKeyList()) {
            try {
                String topic = "";
                if (StringUtils.isNotBlank(iotMqttConfig.getShareGroupName())) {
                    //如果配置文件设置了共享订阅group则走共享订阅逻辑
                    //共享订阅topic：$share/default-group/app/{productKey}/event
                    topic = "$share/" + iotMqttConfig.getShareGroupName() + "/app/" + product + "/event";
                } else {
                    //没设置共享订阅group按原本规则走
                    topic = "$app/" + product + "/notification";
                }
                String finalTopic = topic;
                mqttAsyncClient.subscribe(topic, 0, null,
                        new IMqttActionListener() {
                            @Override
                            public void onSuccess(IMqttToken iMqttToken) {
                                log.info("NetIotMqttClientSubscribeOnSuccess, topic={}", finalTopic);
                            }

                            @Override
                            public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
                                log.info("NetIotMqttClientSubscribeOnFailure, topic={}", finalTopic);
                            }
                        });
            } catch (Exception e) {
                log.info("NetIotMqttClientSubscribeError", e);
            }
        }
    }


}
