package com.yeejoin.amos.boot.module.jyjc.biz.listener;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.jyjc.api.enums.JYJCTypeEnum;
import com.yeejoin.amos.boot.module.jyjc.api.enums.TopicEnum;
import com.yeejoin.amos.boot.module.jyjc.api.model.InspectionEquipInfoModel;
import com.yeejoin.amos.boot.module.jyjc.biz.listener.message.BizMessage;
import com.yeejoin.amos.boot.module.jyjc.biz.rule.InspectionEquipInfo;
import com.yeejoin.amos.boot.module.ymt.api.entity.RegistrationInfo;
import com.yeejoin.amos.boot.module.ymt.api.mapper.RegistrationInfoMapper;
import com.yeejoin.amos.component.robot.AmosRequestContext;
import com.yeejoin.amos.component.rule.RuleTrigger;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.component.emq.EmqxListener;
import org.typroject.tyboot.core.foundation.context.RequestContext;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import static com.alibaba.fastjson.JSON.parseObject;
import static com.alibaba.fastjson.JSON.toJSONString;
import static com.yeejoin.amos.boot.module.jyjc.api.enums.CategoryEnum.getCategoryByType;

/**
 * @author Administrator
 */
@Component
@Slf4j
public class InspectionOrgRefreshListener extends EmqxListener {
    private static final BlockingQueue<BizMessage> BLOCKING_QUEUE = new LinkedBlockingQueue<>();

    @Value("${inspection.rule.project-name:报检规则}")
    private String ruleName;
    @Autowired
    private EmqKeeper emqKeeper;
    @Autowired
    private RuleTrigger ruleTrigger;
    @Autowired
    private AmosRequestContext amosRequestContext;
    @Autowired
    private RegistrationInfoMapper registrationInfoMapper;

    @Value("${spring.application.name}")
    private String applicationName;

    private static final int repeatTime = 2;

    @Autowired
    RedisUtils redisUtils;

    @Override
    public void processMessage(String topic, MqttMessage message) {
        if (log.isInfoEnabled()) {
            log.info("收到消息主题：{},消息内容：{}", topic, message.toString());
        }
        BLOCKING_QUEUE.add(new BizMessage(topic, message));
    }

    @PostConstruct
    public void init() throws Exception {
        emqKeeper.subscript(this.buildShareTopic(TopicEnum.INSPECTION_LIST_REFRESH.getTopic()), 2, this);
        Executors.newSingleThreadExecutor().submit(this::takeMsg);
    }

    private String buildShareTopic(String topic) {
        return "$share/" + applicationName + "/" + topic;
    }

    private void takeMsg() {
        while (true) {
            try {
                BizMessage bizMessage = BLOCKING_QUEUE.take();
                // 解决前端组件在属性变化时重复发送两次问题
                if (!redisUtils.hasKey(bizMessage.getTopic())) {
                    redisUtils.set(bizMessage.getTopic(), true, repeatTime);
                    processBizMessage(bizMessage);
                } else {
                    log.warn("消息在{}秒内重复，", repeatTime);
                }
            } catch (Exception e) {
                log.error("数据处理失败", e);
            }
        }
    }

    private void processBizMessage(BizMessage bizMessage) {
        byte[] payload = bizMessage.getMessage().getPayload();

        InspectionEquipInfoModel equipInfoModel = parseObject(new String(payload, StandardCharsets.UTF_8), InspectionEquipInfoModel.class);
        RegistrationInfo registrationInfo = fetchRegistrationInfo(equipInfoModel.getRecord());
        InspectionEquipInfo inspectionEquipInfo = new InspectionEquipInfo();
        if (registrationInfo == null) {
            log.warn("未找到设备，报检规则匹配流程结束！");
            return;
        }
        inspectionEquipInfo.setEquCategory(registrationInfo.getEquCategory());
        inspectionEquipInfo.setEquList(registrationInfo.getEquList());
        inspectionEquipInfo.setEquDefine(registrationInfo.getEquDefine());
        inspectionEquipInfo.setComponentKey(bizMessage.getTopic().split("/")[0]);
        inspectionEquipInfo.setInspectionType(equipInfoModel.getInspectionType());
        inspectionEquipInfo.setRecord(equipInfoModel.getRecord());
        inspectionEquipInfo.setBizType(getCategoryByType(JYJCTypeEnum.of(inspectionEquipInfo.getInspectionType())));
        touchRule(inspectionEquipInfo);
    }

    private RegistrationInfo fetchRegistrationInfo(String record) {
        return registrationInfoMapper.selectOne(
                Wrappers.<RegistrationInfo>lambdaQuery().select(RegistrationInfo::getRecord, RegistrationInfo::getEquCategory,
                        RegistrationInfo::getEquDefine, RegistrationInfo::getEquList)
                        .eq(RegistrationInfo::getRecord, record));
    }

    private void touchRule(InspectionEquipInfo inspectionEquipInfo) {
        if (log.isInfoEnabled()) {
            log.info("发送规则的消息对象:{}", toJSONString(inspectionEquipInfo));
        }

        RequestContext.setToken(amosRequestContext.getToken());
        RequestContext.setAppKey(amosRequestContext.getAppKey());
        RequestContext.setProduct(amosRequestContext.getProduct());
        // 2.调用规则
        try {
            ruleTrigger.publish(inspectionEquipInfo, ruleName + "/" + inspectionEquipInfo.getBizType(), null);
        } catch (Exception e) {
            log.error("调用规则触发风险模型失败", e);
        }
    }
}
