package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.station.function;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesPartService;
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.apiservice.serviceimpl.step.MesAssemblyShowNosortStepService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step.method.MesWorkOrderCheckCompleteQtyStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProdRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionAssemblyContext;
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.BaseSwsService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.IShippingDispatchService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.function.IFsmModuleFunctionService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.util.MesPcnConstWords;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.model.ButtonDynamicModel;
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.repository.*;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Description : 原料调配输入重量弹框接口实现【输入原料调配弹框重量弹框】
 **/
@Service
public class MesFunctionDialogInputRawMixWeightService extends BaseSwsService implements IFsmModuleFunctionService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IShippingDispatchService shippingDispatchService;

    @Autowired
    private MesRawMixCfgDetailRepository rawMixCfgDetailRDao;

    @Autowired
    private MesRawSnWeightRecordRepository rawSnWeightRecordRDao;
    @Autowired
    private MesRawWeightCfgRepository rawWeightCfgRDao;
    @Autowired
    private MesAssemblyShowNosortStepService assemblyShowNosortStepService;

    @Override
    public Boolean doFunction(StationRequestBean reqBean, StationResultBean resultBean, ButtonDynamicModel buttonDynamicModel) {
        //页面渲染数据集
        final String organizeCode = reqBean.getOrganizeCode();
        StepResult stepResult = StepResult.getSuccessComplete();

        this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(buttonDynamicModel.getFunctionValue()),
                String.format("生产线[%s]工位[%s]调配原料数量弹框提交成功,请等待验证!提交信息[%s]", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), buttonDynamicModel.getFunctionValue()),
                MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT);

        final double inputQty = new Double(buttonDynamicModel.getFunctionValue());
        if (inputQty <= 0) {
            this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(buttonDynamicModel.getFunctionValue()),
                    String.format("输入数量[%s]不能小于等于0", inputQty),
                    MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            return false;
        }
        //获取工位当前设备信息
        MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchCurCellEquipment(reqBean);
        //配置错误 抛出异常
        if (!productionProcessContext.getSuccess()) {
            this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(buttonDynamicModel.getFunctionValue()),
                    productionProcessContext.getMessage(),
                    MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            return false;
        }

        //获取上下文产品加工规则数据信息集合
        List<MesProdRuleContext> prodRuleContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);
        if (CollectionUtils.isEmpty(prodRuleContextList)) {
            this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(buttonDynamicModel.getFunctionValue()),
                    "当前不存在产品加工规则信息,请重置工序解决!",
                    MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
            return false;
        }

        boolean bOverCapacity = false;
        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();
        if (doHandleProductionAssemblyContext(organizeCode, workCenter, prodRuleContextList, buttonDynamicModel.getFunctionValue(), stepResult)) {
            if (isAllAssemblyMatchRawMix(workCenter, prodRuleContextList)) {
                if (!checkRawMixWeight(organizeCode, workCenter, prodRuleContextList, reqBean.getUserInfo())) {
                    this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(buttonDynamicModel.getFunctionValue()),
                            "输入数量超出了容差范围",
                            MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
                    bOverCapacity = true;
                }
            }
        } else {
            bOverCapacity = true;
            this.sendMessage(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(buttonDynamicModel.getFunctionValue()),
                    stepResult.getMsg(),
                    MesPcnEnumUtil.STATION_BUSI_TYPE.MESSAGE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
        }
        productionDispatchContextStepService.dispatchProdRuleDataContext(reqBean, prodRuleContextList);
        if (bOverCapacity) {
            assemblyShowNosortStepService.showProductionAssembly(reqBean, resultBean, productionProcessContext.getWorkCenter(), prodRuleContextList);
        }

        reqBean.setClientInfo(shippingDispatchService.getActorClientInfo(reqBean));
        reqBean.setInterfaceType(MesPcnConstWords.SHIPPING);
        reqBean.setBusiType(MesPcnEnumUtil.ACTOR_RECEIVE_STRATEGY.WS_CMD_DO_SCAN.getCode());
        reqBean.setButtonCode(buttonDynamicModel.getButtonCode());
        reqBean.setStepDialogStatus(true);
        shippingDispatchService.sendScanQueueNextExec(reqBean);
        return !bOverCapacity;
    }

    private boolean doHandleProductionAssemblyContext(String organizeCode, MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList, String qty, StepResult stepResult) {
        final double rawWeight = new Double(qty);
        stepResult.setCompleted(true);
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {
            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getIsMatchRawMix())) {
                continue;
            }

            MesProductionAssemblyContext findAssemblyContext = null;
            List<MesProductionAssemblyContext> productionAssemblyContextList = prodRuleContext.getAssemblyDataContext(workCenter);
            for (MesProductionAssemblyContext productionAssemblyContext : productionAssemblyContextList) {
                if (StringUtils.isEmpty(productionAssemblyContext.getIsCheckedRawMix()) && Objects.equals(productionAssemblyContext.getAssemblyStatus(), MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_10.getValue())) {
                    double remainQty = getRemainQty(organizeCode, productionAssemblyContext.getAssemblyPartNo());
                    if (rawWeight > remainQty) {
                        productionAssemblyContext.setIsCheckedRawMix(null);
                        productionAssemblyContext.setAssemblyStatus(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue());
                        productionAssemblyContext.setAssemblySn(null);

                        stepResult.setCompleted(false);
                        stepResult.setMsg(String.format("零件号[%s], 输入数量[%s], 剩余数量[%s]不足!", productionAssemblyContext.getAssemblyPartNo(), rawWeight, remainQty));
                    } else {
                        productionAssemblyContext.setQty(rawWeight);
                        productionAssemblyContext.setIsCheckedRawMix("1");
                    }
                    findAssemblyContext = productionAssemblyContext;
                    break;
                }
            }

            //存在匹配成功的数据
            if (findAssemblyContext != null) {
                prodRuleContext.assemblyDataJson(productionAssemblyContextList);
                return stepResult.isCompleted();
            }
        }

        stepResult.setCompleted(false);
        stepResult.setMsg("未匹配到装配原料，请重新扫描装配件原料！");
        return false;
    }

    private boolean isAllAssemblyMatchRawMix(MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList) {
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {
            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getIsMatchRawMix())) {
                continue;
            }

            List<MesProductionAssemblyContext> productionAssemblyContextList = prodRuleContext.getAssemblyDataContext(workCenter);
            for (MesProductionAssemblyContext productionAssemblyContext : productionAssemblyContextList) {
                if (StringUtils.isEmpty(productionAssemblyContext.getIsCheckedRawMix())) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean checkRawMixWeight(String organizeCode, MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList, String userName) {
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {
            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getIsMatchRawMix())) {
                continue;
            }

            List<MesRawMixCfgDetail> rawMixCfgDetailList = rawMixCfgDetailRDao.findByProperty(
                    new String[]{"organizeCode", "isValid", "isDeleted", "outPartNo"},
                    new Object[]{organizeCode, CommonEnumUtil.IS_VAILD.VAILD.getValue(), CommonEnumUtil.IS_DEAL.NO.getValue(), prodRuleContext.getOutPartNo()});
            if (CollectionUtils.isEmpty(rawMixCfgDetailList)) {
                continue;
            }
            Map<String, Map.Entry<Double, Double>> partWeightPercent = new HashMap<>();
            for (MesRawMixCfgDetail rawMixCfgDetail : rawMixCfgDetailList) {
                if (StringUtils.isEmpty(rawMixCfgDetail.getPartNo()) || rawMixCfgDetail.getPercent() == null) {
                    continue;
                }
                double percent = rawMixCfgDetail.getPercent();
                double rangeRate = rawMixCfgDetail.getRangeRate() != null ? rawMixCfgDetail.getRangeRate() : 0.0;
                partWeightPercent.put(rawMixCfgDetail.getPartNo(), new AbstractMap.SimpleEntry<>(percent - rangeRate, percent + rangeRate));
            }

            boolean flag = true;
            List<MesProductionAssemblyContext> productionAssemblyContextList = prodRuleContext.getAssemblyDataContext(workCenter);
            double totalQty = productionAssemblyContextList.stream().mapToDouble(MesProductionAssemblyContext::getQty).sum();
            for (MesProductionAssemblyContext productionAssemblyContext : productionAssemblyContextList) {
                Map.Entry<Double, Double> rangeRate = partWeightPercent.get(productionAssemblyContext.getAssemblyPartNo());
                if (null == rangeRate) {
                    continue;
                }

                double curPercent = productionAssemblyContext.getQty() / totalQty;
                curPercent = curPercent * 100;
                if (curPercent < rangeRate.getKey() || curPercent > rangeRate.getValue()) {
                    flag = false;
                    break;
                }
            }
            if (!flag) {
                for (MesProductionAssemblyContext productionAssemblyContext : productionAssemblyContextList) {
                    productionAssemblyContext.setIsCheckedRawMix(null);
                    productionAssemblyContext.setQty(0.0);
                    productionAssemblyContext.setAssemblySn(null);
                    productionAssemblyContext.setAssemblyStatus(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue());
                }
                prodRuleContext.assemblyDataJson(productionAssemblyContextList);
                return false;
            }
        }
        return true;
    }

    private double getRemainQty(String organizeCode, String partNo) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(partNo, "partNo", ddlPackBean);
        DdlPreparedPack.getOrderBy("createDatetime", CommonEnumUtil.ASC_OR_DESC.DESC.getValue(), ddlPackBean);
        MesRawSnWeightRecord record = rawSnWeightRecordRDao.getByProperty(ddlPackBean);
        if (record != null) {
            return record.getNetWeight();
        }

        MesRawWeightCfg weightCfg = rawWeightCfgRDao.getByProperty(new String[]{"organizeCode", "isValid", "isDeleted", "partNo"},
                new Object[]{organizeCode, CommonEnumUtil.IS_VAILD.VAILD.getValue(), CommonEnumUtil.IS_DEAL.NO.getValue(), partNo});
        if (weightCfg == null) {
            return 0.0;
        }
        return weightCfg.getNetWeight();
    }
}
