package com.yeejoin.amos.api.openapi.face.service;


import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.yeejoin.amos.api.openapi.constant.Constant;
import com.yeejoin.amos.api.openapi.face.model.*;
import com.yeejoin.amos.boot.module.cylinder.api.dto.CylinderFillingMessage;
import com.yeejoin.amos.boot.module.cylinder.api.dto.CylinderFillingMessageModel;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.component.cache.Redis;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 气瓶service
 */
@Component
public class CylinderService {

    private static final Logger logger = LogManager.getLogger(CylinderService.class);

    @Autowired
    private final RedisTemplate redisTemplate;
    private final CylinderFillingDataValidationService cylinderFillingDataValidationService;
    private final TmCylinderFillingMessageService cylinderFillingMessageService;
    private final EmqKeeper emqKeeper;
    private final TmCylinderFillingCheckService cylinderFillingCheckService;
    private final TmCylinderFillingRecordService cylinderFillingRecordService;
    private final TmCylinderFillingService cylinderFillingService;

    private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private final BlockingQueue<CylinderFillingMessageModel> blockingQueue = new LinkedBlockingQueue<>();

    public CylinderService(RedisTemplate redisTemplate, CylinderFillingDataValidationService cylinderFillingDataValidationService, TmCylinderFillingMessageService cylinderFillingMessageService, EmqKeeper emqKeeper, TmCylinderFillingCheckService cylinderFillingCheckService, TmCylinderFillingRecordService cylinderFillingRecordService, TmCylinderFillingService cylinderFillingService) {
        this.redisTemplate = redisTemplate;
        this.cylinderFillingDataValidationService = cylinderFillingDataValidationService;
        this.cylinderFillingMessageService = cylinderFillingMessageService;
        this.emqKeeper = emqKeeper;
        this.cylinderFillingCheckService = cylinderFillingCheckService;
        this.cylinderFillingRecordService = cylinderFillingRecordService;
        this.cylinderFillingService = cylinderFillingService;
    }

    @DSTransactional
    public void cylinderFillingHandler(String fillingData) throws MqttException {
        String token = RequestContext.getToken();
        AgencyUserModel me = Privilege.agencyUserClient.getme().getResult();
        String tokenKey = Redis.genKey(Constant.TOKEN_PREFIX, token);
        BizTokenModel bizTokenModel = (BizTokenModel) this.redisTemplate.opsForValue().get(tokenKey);

        JSONObject jsonobject = JSONObject.fromObject(fillingData);
        CylinderFillingMessage cylinderFillingMessage = new CylinderFillingMessage();
        cylinderFillingMessage.setTime(simpleDateFormat.format(new Date()));
        cylinderFillingMessage.setFillingCompanyName(me.getCompanys().get(0).getCompanyName());
        cylinderFillingMessage.setOrgCode(me.getCompanys().get(0).getOrgCode());
        cylinderFillingMessage.setAppId(bizTokenModel.getAppId());

        JSONArray validateResult = validateFillingData(jsonobject, cylinderFillingMessage);
        if (!validateResult.isEmpty()) {
            throw new BadRequest(validateResult.toString());
        }

        TmCylinderFillingModelList cylinderFillingModelList = com.alibaba.fastjson.JSONObject.parseObject(fillingData, TmCylinderFillingModelList.class);

        List<TmCylinderFillingModel> fillingBeforeList = cylinderFillingModelList.getFillingBefore();
        List<TmCylinderFillingRecordModel> fillingList = cylinderFillingModelList.getFilling();
        List<TmCylinderFillingCheckModel> fillingAfterList = cylinderFillingModelList.getFillingAfter();
        if (ValidationUtil.isEmpty(fillingBeforeList) && ValidationUtil.isEmpty(fillingList) && ValidationUtil.isEmpty(fillingAfterList)) {
            throw new BadRequest("液化气体气瓶充装信息-充装前检查信息、液化气体气瓶充装信息-充装记录信息、液化气体气瓶充装信息-充装后复查信息为空.");
        }
        cylinderFillingService.createCylinderFillingBefore(fillingBeforeList);
        cylinderFillingRecordService.createCylinderFilling(fillingList);
        cylinderFillingCheckService.createCylinderFillingAfter(fillingAfterList);

        CylinderFillingMessageModel cylinderFillingMessageModel = new CylinderFillingMessageModel();
        BeanUtils.copyProperties(cylinderFillingMessage, cylinderFillingMessageModel);
        cylinderFillingMessageModel.setAppId(bizTokenModel.getAppId());
        cylinderFillingMessageService.createWithModel(cylinderFillingMessageModel);
        emqKeeper.getMqttClient().publish("openapi/cylinder/filling", JSONObject.fromObject(cylinderFillingMessage).toString().getBytes(), 2, false);
    }

//    @Transactional
    public JSONArray validateFillingData(JSONObject jsonobject, CylinderFillingMessage cylinderFillingLogMessage) throws MqttException {
        CylinderFillingDataValidationResultModel validateResult = null;

        try {
            validateResult = cylinderFillingDataValidationService.validateFilling(jsonobject);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("液化气体气瓶充装信息上报，数据校验失败");
            cylinderFillingLogMessage.setMessage(e.getMessage());
        }

        JSONArray errorData = new JSONArray();

        if (!ObjectUtils.isEmpty(validateResult)) {
            cylinderFillingLogMessage.setCylinderNumber(validateResult.getCylinderNumber());
            List<String> message = new ArrayList<>();
            int errorNumber = 0;
            JSONObject error = new JSONObject();
            if (!ObjectUtils.isEmpty(validateResult.getBeforeErrorData())) {
                errorNumber += validateResult.getBeforeErrorData().size();
                error.put("充装前检查错误数据：", validateResult.getBeforeErrorData());
                message.add("充装前检查数据异常气瓶数：" + validateResult.getBeforeErrorCylinderNumber());
                errorData.add(error);
            }

            if (!ObjectUtils.isEmpty(validateResult.getRecordErrorData())) {
                errorNumber += validateResult.getRecordErrorData().size();
                error.put("充装错误数据：", validateResult.getRecordErrorData());
                message.add("充装记录数据异常气瓶数：" + validateResult.getRecordErrorCylinderNumber());
                errorData.add(error);
            }

            if (!ObjectUtils.isEmpty(validateResult.getAfterErrorData())) {
                errorNumber += validateResult.getAfterErrorData().size();
                error.put("充装后错误数据：", validateResult.getAfterErrorData());
                message.add("充装后复查数据异常气瓶数：" + validateResult.getAfterErrorCylinderNumber());
                errorData.add(error);
            }

            if (!ObjectUtils.isEmpty(validateResult.getSeqCodeErrorData())) {
                errorNumber += validateResult.getSeqCodeErrorData().size();
                error.put("气瓶信息不存在：", validateResult.getSeqCodeErrorData());
                message.add("气瓶信息不存在数量：" + validateResult.getSeqCodeErrorData().size() + "个");
                errorData.add(error);
            }

            if (errorNumber <= 0) {
                cylinderFillingLogMessage.setMessage("液化气体气瓶充装信息成功数：" + validateResult.getSuccessCylinderNumber() + "条");
            } else {
                cylinderFillingLogMessage.setMessage(String.join("条; ", message));
//                cylinderFillingMessageService.createWithModel(cylinderFillingMessageModel);
                emqKeeper.getMqttClient().publish("openapi/cylinder/filling", JSONObject.fromObject(cylinderFillingLogMessage).toString().getBytes(), 2, false);
            }
            CylinderFillingMessageModel cylinderFillingMessageModel = new CylinderFillingMessageModel();
            BeanUtils.copyProperties(cylinderFillingLogMessage, cylinderFillingMessageModel);

            // 充装信息概览放入blockingQueue
            blockingQueue.add(cylinderFillingMessageModel);
        } else {
            errorData.add(new JSONObject().put("数据校验失败", "数据校验失败"));
        }
        return errorData;
    }

    @PostConstruct
    void init() {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 3; i++) {
            executorService.execute(() -> {
                try {
                    while (true) {
                        logger.info("处理气瓶对接错误信息入库~开始");
                        CylinderFillingMessageModel cylinderFillingMessageModel = blockingQueue.take();
                        cylinderFillingMessageService.createWithModel(cylinderFillingMessageModel);
                        logger.info("处理气瓶对接错误信息入库~完成");
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    logger.error("处理气瓶对接错误信息入库异常", e);
                    throw new RuntimeException(e);
                }
            });
        }
    }
}
