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

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.method.IMesPackageNoGenerateStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesPackageDataContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesPackageRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProdRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPartContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.actor.shipping.dispatch.IFsmRouteDataService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseSwsService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.function.IFsmModuleFunctionService;
import cn.estsh.i3plus.mes.pcn.util.PojoAttrUtil;
import cn.estsh.i3plus.mes.pcn.util.StringUtil;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesPackage;
import cn.estsh.i3plus.pojo.mes.model.*;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description : 工位参数按钮事件接口实现【零件打包】
 **/
@Slf4j
@Service
public class MesFunctionPackagePartService extends BaseSwsService implements IFsmModuleFunctionService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesPackageNoGenerateStepService packageNoGenerateStepService;

    @Autowired
    private IFsmRouteDataService fsmRouteDataService;

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Object doCustomApiDispatch(StationRequestBean reqBean, StationResultBean resultBean, ButtonDynamicModel buttonDynamicModel) {

        //页面渲染数据集
        Map<String, Object> resultMap = new HashMap<>();

        //工步结果,用于信息传递的对象
        StepResult stepResult;

        //前端传递的参数
        MesPackageDataContext packageDataContext = StringUtils.isEmpty(buttonDynamicModel.getFunctionValue()) ? null : JSONObject.parseObject(buttonDynamicModel.getFunctionValue(), MesPackageDataContext.class);

        //初始化界面
        if (null == packageDataContext || StringUtils.isEmpty(packageDataContext.getBusiType())) {

            //获取上下文产出零件信息
            List<MesProductionPartContext> productionPartContextList = productionDispatchContextStepService.getProductionPartContext(reqBean);

            //验证是否存在加工单
            Boolean isExistOrder = checkIsExistOrder(productionPartContextList);

            //列名称
            List<AttrBean> attrBeanList = dataAttrList(isExistOrder);

            resultMap.put(MesPcnExtConstWords.ATTR_BEAN_LIST, attrBeanList);

            //获取上下文产品加工规则数据信息
            List<MesProdRuleContext> prodRuleContextList = null;
            if (CollectionUtils.isEmpty(productionPartContextList)) prodRuleContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);

            //当前没有产成零件时,设置 IS_SELECT_PART=1 则支持开窗选零件
            if (CollectionUtils.isEmpty(productionPartContextList) && CollectionUtils.isEmpty(prodRuleContextList)) resultMap.put(MesPcnExtConstWords.IS_SELECT_PART, CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());

            if (CollectionUtils.isEmpty(productionPartContextList) && CollectionUtils.isEmpty(prodRuleContextList) && (null == packageDataContext || StringUtils.isEmpty(packageDataContext.getPartNo()))) {
                resultMap.put(MesPcnExtConstWords.DATA_TYPE, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT.getValue());
                return packResultMap(reqBean, resultBean, resultMap, String.format("生产线[%s]工位[%s]零件打包:请选择打包零件编码!", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode()));
            }

            //获取包装规则信息
            Map<String, MesPackageRuleContext> packageRuleContextMap = productionProcessContextStepService.getPackageRuleContext(reqBean);
            if (CollectionUtils.isEmpty(packageRuleContextMap)) packageRuleContextMap = new HashMap<>();
            Integer initQty = packageRuleContextMap.size();

            //列表数据
            List<MesPackageDataContext> resultList = new ArrayList<>();

            stepResult = StepResult.getSuccessComplete();

            //根据上下文产出零件信息封装列表数据
            if (!CollectionUtils.isEmpty(productionPartContextList)) packResultList2Ppc(reqBean, stepResult, productionPartContextList, isExistOrder, packageRuleContextMap, resultList);
                //根据上下文产品加工规则数据信息封装列表数据
            else if (!CollectionUtils.isEmpty(prodRuleContextList)) packResultList2Prc(reqBean, stepResult, prodRuleContextList, packageRuleContextMap, resultList);
                //根据用户选择的零件信息封装列表数据
            else packResultList2PartNo(reqBean, stepResult, packageDataContext.getPartNo(), packageRuleContextMap, resultList);

            //保存包装规则信息
            if (initQty != packageRuleContextMap.size()) productionProcessContextStepService.dispatchPackageRuleContext(reqBean, packageRuleContextMap);

            if (!StringUtils.isEmpty(stepResult.getMsg())) {
                resultMap.put(MesPcnExtConstWords.DATA_TYPE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT.getValue());
                packResultMap(reqBean, resultBean, resultMap, String.format("生产线[%s]工位[%s]零件打包:%s!", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), stepResult.getMsg()));
            }

            resultMap.put(MesPcnExtConstWords.DATA, resultList);
            return resultMap;
        }

        resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PICK.getValue()).scanInfo(String.format("零件号[%s]数量[%s]包装规格数量[%s]", packageDataContext.getPartNo(), packageDataContext.getQty(), packageDataContext.getPackSpecQty()));

        resultMap.put(MesPcnExtConstWords.DATA_TYPE, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT.getValue());
        if (StringUtils.isEmpty(packageDataContext.getPartNo()) || StringUtils.isEmpty(packageDataContext.getQty()) || StringUtils.isEmpty(packageDataContext.getPackageCode())) {
            return packResultMap(reqBean, resultBean, resultMap, String.format("生产线[%s]工位[%s]零件打包:零件编码[%s]缺少必要主数据!", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), packageDataContext.getPartNo()));
        }

        stepResult = StepResult.getSuccessComplete();
        //零件打包不写包装明细数据, 默认赋值[仅统计包装], 生成虚拟条码
        packageDataContext.setGenerateType(MesExtEnumUtil.PACKING_RULE_GENERATE_TYPE.PACKAGE.getValue());
        packageDataContext.setPartPackWorkOrderNo(packageDataContext.getWorkOrderNo());
        try {
            //零件打包业务处理
            stepResult.setDataCollection(new ArrayList());
            packageNoGenerateStepService.doHandlePackagePart(reqBean, resultBean, stepResult, packageDataContext);
        } catch (ImppBusiException e) {
            stepResult.msg(e.getErrorDetail());
        } catch (Exception e) {
            String error = String.format("生产线[%s]工位[%s]零件打包%s", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), fsmRouteDataService.handleFsmCfgOrDefault(reqBean, MesPcnEnumUtil.FSM_CFG.FSM_EXCEPTION_MSG.getCode()));
            this.cacheException(reqBean, StringUtil.toLowerCaseFirst(this.getClass().getSimpleName()), error, e, false);
            stepResult.msg(error);
        }
        //判断零件打包的执行结果
        if (!StringUtils.isEmpty(stepResult.getMsg())) {
            return packResultMap(reqBean, resultBean, resultMap,
                    String.format("生产线[%s]工位[%s]零件打包失败,%s", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), stepResult.getMsg()));
        }

        resultMap.put(MesPcnExtConstWords.DATA_TYPE, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT.getValue());
        return packResultMap(reqBean, resultBean, resultMap, String.format("零件号[%s]零件打包成功!包装条码%s打印成功!",
                packageDataContext.getPartNo(), ((List<MesPackage>) stepResult.getDataCollection()).stream().filter(o -> null != o).map(MesPackage::getPackageNo).collect(Collectors.toList()).toString()));

    }

    //返回提示信息
    private Map<String, Object> packResultMap(StationRequestBean reqBean, StationResultBean resultBean, Map<String, Object> resultMap, String message) {
        this.sendMessage(reqBean, resultBean, message, MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.EXP_TEXT);
        resultMap.put(MesPcnExtConstWords.MESSAGE, message);
        return resultMap;
    }

    //验证是否存在加工单
    private Boolean checkIsExistOrder(List<MesProductionPartContext> productionPartContextList) {
        Optional<MesProductionPartContext> optional = CollectionUtils.isEmpty(productionPartContextList) ? null :
                productionPartContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkOrderNo()))).findFirst();
        return (null != optional && optional.isPresent()) ? true : false;
    }

    //列名称
    public List<AttrBean> dataAttrList(Boolean isExistOrder) {
        List<AttrBean> attrBeanList = new ArrayList<>();
        if (isExistOrder) PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.WORK_ORDER_NO, "加工单号");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.PART_NO, "零件编码");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.PART_NAME, "零件名称");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.QTY, "装箱个数");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.PACK_SPEC_QTY, "包装规格数量");
        return attrBeanList;
    }

    //根据上下文产出零件信息封装列表数据
    private void packResultList2Ppc(StationRequestBean reqBean, StepResult stepResult, List<MesProductionPartContext> productionPartContextList, Boolean isExistOrder,
                                    Map<String, MesPackageRuleContext> packageRuleContextMap, List<MesPackageDataContext> resultList) {
        List<MesProductionPartContext> filterList;
        if (isExistOrder) {
            filterList = productionPartContextList.stream().filter(o -> (null != o && o.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0))
                    .distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesProductionPartContext::getWorkOrderNo))), ArrayList::new));
        } else {
            filterList = productionPartContextList.stream().filter(o -> (null != o && o.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0))
                    .distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesProductionPartContext::getPartNo))), ArrayList::new));
        }

        for (MesProductionPartContext productionPartContext : filterList) {
            if (null == productionPartContext) continue;
            MesPackageDataContext packageDataContext = new MesPackageDataContext();

            MesPackageRuleContext packageRuleContext = packageRuleContextMap.get(productionPartContext.getPartNo());
            if (null == packageRuleContext) {
                packageRuleContext = packageNoGenerateStepService.getPackageRuleContext(reqBean, stepResult, productionPartContext.getPartNo(), true);
                if (null != packageRuleContext) packageRuleContextMap.put(productionPartContext.getPartNo(), packageRuleContext);
            }
            if (null != packageRuleContext) BeanUtils.copyProperties(packageRuleContext, packageDataContext);

            packageDataContext.setWorkOrderNo(productionPartContext.getWorkOrderNo());
            packageDataContext.setQty(isExistOrder ? productionPartContext.getQty() : packageDataContext.getPackSpecQty());
            resultList.add(packageDataContext);
        }
    }

    //根据上下文产品加工规则数据信息封装列表数据
    private void packResultList2Prc(StationRequestBean reqBean, StepResult stepResult, List<MesProdRuleContext> prodRuleContextList,
                                    Map<String, MesPackageRuleContext> packageRuleContextMap, List<MesPackageDataContext> resultList) {
        List<MesProdRuleContext> filterList = prodRuleContextList.stream().filter(o -> null != o)
                .distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesProdRuleContext::getOutPartNo))), ArrayList::new));

        for (MesProdRuleContext prodRuleContext : filterList) {
            if (null == prodRuleContext) continue;
            MesPackageDataContext packageDataContext = new MesPackageDataContext();

            MesPackageRuleContext packageRuleContext = packageRuleContextMap.get(prodRuleContext.getOutPartNo());
            if (null == packageRuleContext) {
                packageRuleContext = packageNoGenerateStepService.getPackageRuleContext(reqBean, stepResult, prodRuleContext.getOutPartNo(), true);
                if (null != packageRuleContext) packageRuleContextMap.put(prodRuleContext.getOutPartNo(), packageRuleContext);
            }
            if (null != packageRuleContext) BeanUtils.copyProperties(packageRuleContext, packageDataContext);

            packageDataContext.setQty(packageDataContext.getPackSpecQty());
            resultList.add(packageDataContext);
        }
    }

    //根据用户选择的零件信息封装列表数据
    private void packResultList2PartNo(StationRequestBean reqBean, StepResult stepResult, String partNo,
                                       Map<String, MesPackageRuleContext> packageRuleContextMap, List<MesPackageDataContext> resultList) {
        MesPackageDataContext packageDataContext = new MesPackageDataContext();

        MesPackageRuleContext packageRuleContext = packageRuleContextMap.get(partNo);
        if (null == packageRuleContext) {
            packageRuleContext = packageNoGenerateStepService.getPackageRuleContext(reqBean, stepResult, partNo, true);
            if (null != packageRuleContext) packageRuleContextMap.put(partNo, packageRuleContext);
        }
        if (null != packageRuleContext) BeanUtils.copyProperties(packageRuleContext, packageDataContext);

        packageDataContext.setQty(packageDataContext.getPackSpecQty());
        resultList.add(packageDataContext);
    }

}

