package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step;

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesEquipVariableRwExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionDispatchContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionProcessContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesCellEquipContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionProcessContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentVariable;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentVariableCfg;
import cn.estsh.i3plus.pojo.mes.bean.MesProdRouteOptParam;
import cn.estsh.i3plus.pojo.mes.model.MesEquipVariableRwResult;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.i3plus.pojo.mes.model.StationResultBean;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @Description : 发送允许加工指令工步
 * @Author : wangjie
 **/
@Slf4j
@Service("mesSendProcessCmdStepService")
public class MesSendProcessCmdStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesEquipVariableRwExtService equipVariableRwExtService;

    @Override
    public StepResult execute(StationRequestBean reqBean) {

        StepResult stepResult = StepResult.getSuccessComplete();

        StationResultBean resultBean = new StationResultBean();

        //获取工步参数
        Optional<Map<String, MesProdRouteOptParam>> stepParamMap = getStepParams(reqBean);

        //获取上下文信息
        MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchCurCellEquipment(reqBean, stepParamMap);

        //当前工序已存在发送允许加工指令
        if (!StringUtils.isEmpty(productionDispatchContextStepService.getSendProcessCmdContext(reqBean))) return stepResult;

        //获取生产过程上下文对象有异常信息 抛出异常
        if (!productionProcessContextStepService.getEquipmentVariableCfgList(productionProcessContext).getSuccess()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

        //从上下文的设备数据变量接口逻辑对象集合中取出当前设备信息的逻辑类型对应的接口逻辑对象集合
        List<MesEquipmentVariableCfg> equipmentVariableCfgList = productionProcessContext.getEquipVariableCfgListByVct();

        //根据变量类别[开始处理指令]搜集设备数据变量接口逻辑信息
        equipmentVariableCfgList = productionProcessContextStepService.collectEquipmentVariableCfgList(equipmentVariableCfgList, MesExtEnumUtil.EQUIP_VARIABLE_CFG_CATEGORY.SEND_PROCESS.getValue());

        //当前工位使用的设备
        MesCellEquipContext cellEquipContext = productionProcessContext.getCurCellEquip();

        //配置错误 抛出异常
        if (!productionProcessContextStepService.checkNecessaryEquipmentVariableCfgAndValue(productionProcessContext, cellEquipContext, equipmentVariableCfgList, MesExtEnumUtil.EQUIP_VARIABLE_CFG_CATEGORY.SEND_PROCESS.getValue()).getSuccess())
            stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

        //搜集设备数据变量接口逻辑信息中的二级变量
        List<String> categoryLevelTwoList = productionProcessContextStepService.collectCategoryLevelTwoList(equipmentVariableCfgList);

        //根据变量类型与二级变量获取设备数据变量信息
        List<MesEquipmentVariable> equipmentVariableList = productionProcessContextStepService.findEquipmentVariableList(productionProcessContext, MesExtEnumUtil.EQUIP_VARIABLE_TYPE.PRODUCTION.getValue(), categoryLevelTwoList);

        //配置错误 抛出异常
        if (!productionProcessContextStepService.checkIsEmptyEquipmentVariableList(productionProcessContext, cellEquipContext, equipmentVariableList, MesExtEnumUtil.EQUIP_VARIABLE_TYPE.PRODUCTION, categoryLevelTwoList).getSuccess())
            stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

        //存储生产过程上下文对象
        productionProcessContextStepService.dispatchProductionProcessContext(reqBean, productionProcessContext);

        //发送数据给设备的数据变量
        return execSendProcessCmd(reqBean, resultBean, stepParamMap, stepResult, cellEquipContext, equipmentVariableCfgList, equipmentVariableList, cellEquipContext.getKepwareFlag(equipmentVariableList.get(0).getChannel()));

    }

    private StepResult execSendProcessCmd(StationRequestBean reqBean, StationResultBean resultBean, Optional<Map<String, MesProdRouteOptParam>> stepParamMap, StepResult stepResult,
                                          MesCellEquipContext cellEquipContext, List<MesEquipmentVariableCfg> equipmentVariableCfgList, List<MesEquipmentVariable> equipmentVariableList, String kepwareFlag) {
        //最大重试次数[工步参数]
        Integer maxRetryTimes = getMaxRetryTimes(stepParamMap);

        MesEquipVariableRwResult equipVariableRwResult = null;

        Map<String, List<MesEquipmentVariableCfg>> categoryLevelTwoMap = equipmentVariableCfgList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesEquipmentVariableCfg::getCategoryLevelTwo));

        for (int i = 1; i <= maxRetryTimes; i ++) {

            //写值
            for (MesEquipmentVariable equipmentVariable : equipmentVariableList) {

                equipVariableRwResult = equipVariableRwExtService.writeVariable(categoryLevelTwoMap.get(equipmentVariable.getCategoryLevelTwo()).get(0), equipmentVariable, kepwareFlag);

                if (equipVariableRwResult.getIsSuccessed()) {
                    this.sendMessage(reqBean, new StationResultBean().writeDbLog().checkRepeat(), String.format("[%s]%s", cellEquipContext.getEquipmentName(), equipVariableRwResult.getMessage()), MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT);
                } else {
                    this.sendMessage(reqBean, new StationResultBean().writeDbLog().checkRepeat(), String.format("设备[%s]:允许加工指令发送失败!原因:%s", cellEquipContext.getEquipmentName(), JSONObject.toJSONString(equipVariableRwResult)), MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT);
                    break;
                }

            }

            if (!equipVariableRwResult.getIsSuccessed() && equipVariableRwResult.getIsNoCfg())
                stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), String.format("设备[%s]:允许加工指令发送失败!原因:%s", cellEquipContext.getEquipmentName(), equipVariableRwResult.getMessage()));

            if (equipVariableRwResult.getIsSuccessed())
                return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, String.format("设备[%s]:允许加工指令发送成功!", cellEquipContext.getEquipmentName()));

            stepNonCompleteAndSendMsg(reqBean, resultBean.writeDbLog().checkRepeat(), stepResult, String.format("设备[%s]:允许加工指令发送失败!累计次数[%s]!原因:%s", cellEquipContext.getEquipmentName(), i, equipVariableRwResult.getMessage()));

            //每失败一次 睡眠
            if (i != maxRetryTimes) threadSleep(stepParamMap, MesPcnExtConstWords.READ_FAILURE_SLEEP, MesPcnExtConstWords.READ_FAILURE_SLEEP_DEFAULT_TIME);

        }

        stepSendTaskCompleteAndThrowEx(reqBean, stepResult, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);

        return stepResult;

    }

    //最大重试次数[工步参数]
    private Integer getMaxRetryTimes(Optional<Map<String, MesProdRouteOptParam>> stepParamMap) {
        Integer maxRetryTimes = null;
        try {
            maxRetryTimes = (null != stepParamMap && stepParamMap.isPresent() && stepParamMap.get().containsKey(MesPcnExtConstWords.MAX_RETRY_TIMES)) ? Integer.valueOf(stepParamMap.get().get(MesPcnExtConstWords.MAX_RETRY_TIMES).getParamValue()) : null;
        } catch (NumberFormatException e) {
        }
        return !StringUtils.isEmpty(maxRetryTimes) ? maxRetryTimes : MesPcnExtConstWords.MAX_RETRY_TIMES_DEFAULT;
    }

}
