package com.mortals.xhx.daemon.applicationservice;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.mortals.framework.ap.GlobalSysInfo;
import com.mortals.framework.model.BizLogPdu;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.IMessageProduceService;
import com.mortals.framework.springcloud.service.IApplicationStartedService;
import com.mortals.xhx.common.code.*;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.key.RedisKey;
import com.mortals.xhx.common.utils.SendTask;
import com.mortals.xhx.common.utils.SendTaskThreadPool;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.model.DeviceLogEntity;
import com.mortals.xhx.module.device.service.DeviceLogService;
import com.mortals.xhx.module.device.service.DeviceService;
import com.mortals.xhx.module.platform.model.PlatformEntity;
import com.mortals.xhx.module.platform.service.PlatformService;
import com.mortals.xhx.module.product.model.ProductEntity;
import com.mortals.xhx.module.product.service.ProductService;
import com.mortals.xhx.queue.DefaultTbCoreConsumerService;
import com.mortals.xhx.queue.TbQueueConsumer;
import com.mortals.xhx.queue.TbQueueMsg;
import com.mortals.xhx.queue.TopicPartitionInfo;
import com.mortals.xhx.utils.IotThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.mortals.xhx.common.model.MessageHeader.*;


//@Component
@Slf4j
public class DeviceMsgComsumerStartedService implements IApplicationStartedService {

    @Autowired
    private DefaultTbCoreConsumerService consumerService;
    @Autowired
    private DeviceLogService deviceLogService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private ProductService productService;
    @Autowired
    private PlatformService platformService;
    @Autowired
    private SendTaskThreadPool sendTaskThreadPool;
    @Autowired
    private ICacheService cacheService;

//    @Autowired
//    private IMessageProduceService messageProduceService;

    protected volatile ExecutorService consumersExecutor;


    protected Boolean stopped = false;

    @Override
    public void start() {
        log.info("服务端消费消息服务开始..");
        TbQueueConsumer<TbQueueMsg> mainConsumer = consumerService.getMainConsumer();
        if (!ObjectUtils.isEmpty(mainConsumer)) {
            //订阅所有已激活设备
            Set<TopicPartitionInfo> topicPartitionInfoSet = deviceService.find(new DeviceEntity()
                            //.active(ActiveEnum.已激活.getValue())
                            //.status(StatusEnum.启用.getValue())
                    )
                    .stream()
                    .filter(f -> !ObjectUtils.isEmpty(platformService.get(f.getPlatformId())))
                    .filter(f -> !ObjectUtils.isEmpty(productService.get(f.getProductId())))
                    .map(item -> {
                                PlatformEntity platformEntity = platformService.get(item.getPlatformId());
                                ProductEntity productEntity = productService.get(item.getProductId());
                                String exchangeName = platformEntity.getPlatformSn() + Constant.EXCHANGE_SPLIT + productEntity.getProductCode();
                                return new TopicPartitionInfo(Constant.UPLOAD_TOPIC + item.getDeviceCode(), null, exchangeName);
                            }
                    ).collect(Collectors.toSet());
            mainConsumer.subscribe(topicPartitionInfoSet);
            topicPartitionInfoSet.stream().forEach(item -> {
                log.info("消费线程订阅topic：{}", item.getTopic());
            });
            this.consumersExecutor = Executors.newCachedThreadPool(IotThreadFactory.forName("消费queue线程"));

            consumersExecutor.submit(() -> {
                int waitTime = 50;
                while (!stopped) {
                    try {
                        List<TbQueueMsg> messageList = new ArrayList(32);
                        TbQueueMsg message;
                        for (int i = 0; i < 32; i++) {
                            if (i == 0) {
                                message = consumerService.getComsureQueue().poll(waitTime, TimeUnit.MILLISECONDS);
                            } else {
                                message = consumerService.getComsureQueue().poll();
                            }
                            if (Objects.nonNull(message)) {
                                messageList.add(message);
                            } else {
                                break;
                            }
                        }
                        if (messageList.size() > 0) {
                            log.debug("poll messageQueue messages: {}", JSON.toJSONString(messageList));
                            //异步消息分发
                            AsyncDispatcher dispatcher = new AsyncDispatcher(messageList);
                            sendTaskThreadPool.execute(dispatcher);
                        }

                    } catch (Exception e) {
                        if (!stopped) {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e2) {
                            }
                        }
                    }
                }
                //mainConsumer.commit();
            });
        }
    }

    @Override
    public void stop() {
        log.info("停止服务..");
//        if (mainConsumer != null) {
//            mainConsumer.unsubscribe();
//        }
    }

    @Override
    public int getOrder() {
        return 10;
    }


    class AsyncDispatcher implements Runnable {

        private List<TbQueueMsg> messages;

        AsyncDispatcher(List<TbQueueMsg> messages) {
            this.messages = messages;
        }

        @Override
        public void run() {
            if (Objects.nonNull(messages)) {
                try {
                    for (TbQueueMsg queueMsg : messages) {
                        log.debug("[WRITE MESSAGE] ->message:{}", JSON.toJSONString(queueMsg));
                        //做相应业务,做日志操作
                        String deviceCode = queueMsg.getHeaders().get(DEVICECODE);
                        String messageType = queueMsg.getHeaders().get(MESSAGETYPE);

                        //DeviceReq deviceReq = JSON.parseObject(new String(queueMsg.getData()), DeviceReq.class);
                        DeviceEntity deviceEntity = deviceService.getExtCache(deviceCode);
                        if (!ObjectUtils.isEmpty(deviceEntity)) {
                            cacheService.set(RedisKey.KEY_DEVICE_ONLINE_CACHE + deviceEntity.getDeviceCode(), "", GlobalSysInfo.getParamIntValue(Constant.HEARTBEAT_TIMEOUT, 120));

                            if (deviceEntity.getDeviceStatus() == DeviceStatusEnum.离线.getValue()) {
                                deviceEntity.setOnlineTime(new Date());
                                deviceEntity.setDeviceStatus(DeviceStatusEnum.在线.getValue());
                                deviceService.update(deviceEntity);

                                PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
                                ProductEntity productEntity = productService.get(deviceEntity.getProductId());
                                if (!ObjectUtils.isEmpty(platformEntity) && !ObjectUtils.isEmpty(productEntity)) {
                                    //新增设备通知第三方平台
                                    deviceService.sendThirdParty(deviceEntity, productEntity, platformEntity, DeviceMethodEnum.ONLINE);
                                }
                            }
                            if (!Constant.MESSAGETYPE_HEARTBEAT.equalsIgnoreCase(messageType)) {
                                DeviceLogEntity deviceLogEntity = new DeviceLogEntity();
                                deviceLogEntity.initAttrValue();
                                deviceLogEntity.setTraceID(IdUtil.fastSimpleUUID());
                                deviceLogEntity.setSiteId(deviceEntity.getSiteId());
                                deviceLogEntity.setDeviceId(deviceEntity.getId());
                                deviceLogEntity.setDeviceName(deviceEntity.getDeviceName());
                                deviceLogEntity.setDeviceCode(deviceEntity.getDeviceCode());
                                deviceLogEntity.setMessageHead(messageType);
                                deviceLogEntity.setContent(queueMsg.getData());
                                deviceLogEntity.setLogType(LogTypeEnum.上报事件.getValue());
                                deviceLogEntity.setCreateUserId(1L);
                                deviceLogEntity.setCreateTime(new Date());
                                deviceLogService.save(deviceLogEntity);
                            }
                            //获取exchange,
                            PlatformEntity platformEntity = platformService.get(deviceEntity.getPlatformId());
                            if (!Constant.MESSAGETYPE_HEARTBEAT.equalsIgnoreCase(messageType)
                                    && !ObjectUtils.isEmpty(platformEntity)
                                    && platformEntity.getSendSwitch() == YesNoEnum.YES.getValue()) {
                                if (platformEntity.getSendMsgType() == SendMsgTypeEnum.http.getValue() && !ObjectUtils.isEmpty(platformEntity.getSendUrl())) {
                                    //http方式
                                    //通过线程池进行发送消息
                                    SendTask sendTask = new SendTask(platformEntity.getSendUrl(), queueMsg.getData());
                                    sendTaskThreadPool.execute(sendTask);
                                }
                            }

                        }

                    }
                } catch (Exception ex) {
                    log.error("异常", ex);
                }
            }
        }
    }

}
