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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionProcessContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesPartContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionPartContext;
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.api.iservice.base.IPartService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.mes.pcn.util.StationKvBeanUtil;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesPart;
import cn.estsh.i3plus.pojo.mes.model.StationKvBean;
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 lombok.extern.slf4j.Slf4j;
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.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Description : 缓存零件通用工步方法
 * @Author : wangjie
 **/
@Slf4j
@Service("mesPartDataMapSaveStepService")
public class MesPartDataMapSaveStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IPartService partService;

    //保存零件数据信息
    public StepResult savePartDataMap2PPC(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<MesProductionPartContext> productionPartContextList, Boolean isBackError, Boolean isFilter, Boolean isSave, Boolean isExt) {

        //从一模多腔信息中搜集零件编码并去重
        List<String> partNoList = (productionPartContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()))).map(MesProductionPartContext::getPartNo).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        return savePartDataMap(reqBean, resultBean, stepResult, partNoList, isBackError, isFilter, isSave, isExt);

    }

    //保存零件数据信息
    public StepResult savePartDataMap2PPC(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<MesProductionPartContext> productionPartContextList, Boolean isBackError, Boolean isFilter, Boolean isSave) {

        //从一模多腔信息中搜集零件编码并去重
        List<String> partNoList = (productionPartContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()))).map(MesProductionPartContext::getPartNo).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        return savePartDataMap(reqBean, resultBean, stepResult, partNoList, isBackError, isFilter, isSave, false);

    }

    //保存零件数据信息
    public StepResult savePartDataMap2PPC(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<MesProductionPartContext> productionPartContextList, Boolean isBackError, Boolean isFilter) {

        //从一模多腔信息中搜集零件编码并去重
        List<String> partNoList = (productionPartContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()))).map(MesProductionPartContext::getPartNo).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        return savePartDataMap(reqBean, resultBean, stepResult, partNoList, isBackError, isFilter, true, false);

    }

    //保存零件数据信息
    public StepResult savePartDataMap(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<String> partNoList, Boolean isBackError, Boolean isFilter) {

        return savePartDataMap(reqBean, resultBean, stepResult, partNoList, isBackError, isFilter, true, false);

    }

    //保存零件数据信息 【isBackError=false: 抛出异常】【isFilter=false: 重新查询所有零件；true: 过滤之后查询未缓存的零件之后再进行合并前面已缓存过的零件; isExt=false返回MesPart,true返回MesPartContext】
    public StepResult savePartDataMap(StationRequestBean reqBean, StationResultBean resultBean, StepResult stepResult, List<String> partNoList, Boolean isBackError, Boolean isFilter, Boolean isSave, Boolean isExt) {

        if (CollectionUtils.isEmpty(partNoList)) {
            stepResult.isCompleted(false).msg("获取零件信息失败,零件编码不存在!");
            if (!isBackError) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), stepResult.getMsg());
        }

        //从上下文中取出零件信息集合
        Map<String, ? extends MesPart> partDataMap = productionProcessContextStepService.getPartDataContext(reqBean, isExt);

        //验证上下文中取出零件信息集合是否匹配当前搜集的零件编码
        if (!CollectionUtils.isEmpty(partDataMap) && partDataMap.keySet().containsAll(partNoList)) return stepResult.obj(partDataMap);

        //新零件MAP
        Map<String, MesPart> finalPartDataMap = null;
        Map<String, MesPartContext> finalPartDataExtMap = null;
        if (!isFilter) {
            //根据物料编码集合查询物料信息
            if (!isExt) finalPartDataMap = partService.getPartMap(reqBean.getOrganizeCode(), partNoList);
            else {
                List<MesPart> partList = partService.getPartList(reqBean.getOrganizeCode(), partNoList);
                finalPartDataExtMap = getPartMap(partList);
            }
        } else {
            //已缓存的零件号
            List<String> containPartNoList = CollectionUtils.isEmpty(partDataMap) ? null : partNoList.stream().filter(o -> (!StringUtils.isEmpty(o) && partDataMap.containsKey(o))).collect(Collectors.toList());
            //未缓存的零件号
            List<String> unContainPartNoList = CollectionUtils.isEmpty(partDataMap) ? partNoList : partNoList.stream().filter(o -> (!StringUtils.isEmpty(o) && !partDataMap.containsKey(o))).collect(Collectors.toList());
            //根据未缓存的零件号集合查询物料信息
            if (!isExt) finalPartDataMap = partService.getPartMap(reqBean.getOrganizeCode(), unContainPartNoList);
            else {
                List<MesPart> partList = partService.getPartList(reqBean.getOrganizeCode(), partNoList);
                finalPartDataExtMap = getPartMap(partList);
            }
            //合并零件号
            if ((!CollectionUtils.isEmpty(finalPartDataMap) || !CollectionUtils.isEmpty(finalPartDataExtMap)) && !CollectionUtils.isEmpty(containPartNoList)) {
                for (String partNo : containPartNoList) {
                    if (StringUtils.isEmpty(partNo)) continue;
                    if (!isExt) finalPartDataMap.put(partNo, partDataMap.get(partNo));
                    else finalPartDataExtMap.put(partNo, (MesPartContext) partDataMap.get(partNo));
                }
            }
        }

        //零件信息缺失 抛出异常
        List<String> finalPartList = !isExt ? (CollectionUtils.isEmpty(finalPartDataMap) ? null : new ArrayList<>(finalPartDataMap.keySet())) : (CollectionUtils.isEmpty(finalPartDataExtMap) ? null : new ArrayList<>(finalPartDataExtMap.keySet()));
        List<String> filterList = CollectionUtils.isEmpty(finalPartList) ? null : partNoList.stream().filter(o -> (!StringUtils.isEmpty(o) && !finalPartList.contains(o))).collect(Collectors.toList());

        //保存上下文零件数据信息
        if (!CollectionUtils.isEmpty(finalPartList) && CollectionUtils.isEmpty(filterList)) {
            if (isSave) productionProcessContextStepService.dispatchPartDataContext(reqBean, !isExt ? finalPartDataMap : finalPartDataExtMap);
            return stepResult.obj(!isExt ? finalPartDataMap : finalPartDataExtMap);
        }

        //验证错误 根据isBackError判断是否抛出异常
        stepResult.isCompleted(false).msg(String.format("请检查零件信息,零件编码%s信息不存在!", CollectionUtils.isEmpty(finalPartList) ? partNoList.toString() : filterList.toString()));

        if (!isBackError) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), stepResult.getMsg());

        return stepResult;

    }

    //验证是否全部为空腔
    public Boolean checkIsAllFinishCode(List<MesProductionPartContext> productionPartContextList) {
        Optional<MesProductionPartContext> optional = productionPartContextList.stream().filter(o -> (null != o && o.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0)).findFirst();
        if (null != optional && optional.isPresent()) return false;
        return true;
    }

    //根据是否空腔搜集数据
    public List<MesProductionPartContext> filterProductionPartContext(List<MesProductionPartContext> productionPartContextList, Boolean flag) {
        return flag ? productionPartContextList.stream().filter(o -> (null != o && o.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) == 0)).collect(Collectors.toList()) :
                productionPartContextList.stream().filter(o -> (null != o && o.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0)).collect(Collectors.toList());
    }

    //获取产出零件信息信息
    public List<MesProductionPartContext> getProductionPartContext(StationRequestBean reqBean, MesProductionProcessContext productionProcessContext,
                                                                   List<MesProductionPartContext> productionPartContextList, Map<String, MesPart> partDataMap, List<String> partNoList) {
        partNoList.stream().filter(o -> !StringUtils.isEmpty(o)).forEach(o -> productionPartContextList.add(getProductionPartContextByPartNo(reqBean, o, productionProcessContext, partDataMap)));
        return productionPartContextList;
    }

    private MesProductionPartContext getProductionPartContextByPartNo(StationRequestBean reqBean, String partNo, MesProductionProcessContext productionProcessContext, Map<String, MesPart> partDataMap) {
        if (!partNo.equals(productionProcessContext.getFinishCode())) return new MesProductionPartContext().copyPartNo(reqBean.getOrganizeCode(), partNo, partDataMap.get(partNo).getPartName());
        return new MesProductionPartContext().isFinishCode();
    }

    //封装展示组件MODULE_CONTENT内容
    public List<List<StationKvBean>> getModuleContextData2PartNo(StationRequestBean reqBean, List<MesProductionPartContext> productionPartContextList) {

        List<List<StationKvBean>> dataList = new ArrayList<>();

        List<MesProductionPartContext> orderList = filterProductionPartContext(productionPartContextList, true);
        List<MesProductionPartContext> finishCodeList = filterProductionPartContext(productionPartContextList, false);

        AtomicReference<Integer> index = new AtomicReference<>(0);

        if (!CollectionUtils.isEmpty(orderList)) {
            orderList.forEach(o -> StationKvBeanUtil.addStationKvBeanList(dataList, new ArrayList<>(),
                    new StationKvBean(MesPcnExtConstWords.PART_NO, "零件编码", o.getPartNo()), new StationKvBean(MesPcnExtConstWords.PART_NAME, "零件名称", o.getPartName()),
                    new StationKvBean(MesPcnExtConstWords.CAVITY, "腔数", new StringJoiner(MesPcnExtConstWords.SLANT_R).add(String.valueOf(index.updateAndGet(v -> v + 1))).add(String.valueOf(productionPartContextList.size())).toString())));
        }

        if (!CollectionUtils.isEmpty(finishCodeList)) {
            StationKvBeanUtil.addStationKvBeanList(dataList, new ArrayList<>(), new StationKvBean(MesPcnExtConstWords.CAVITY_FINISH_CODE, "空腔数", String.valueOf(finishCodeList.size())));
        }

        return dataList;
    }

    private Map<String, MesPartContext> getPartMap(List<MesPart> partList) {
        partList = CollectionUtils.isEmpty(partList) ? null :
                partList.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesPart::getPartNo))), ArrayList::new));
        return CollectionUtils.isEmpty(partList) ? null : partList.stream().filter(o -> null != o).collect(Collectors.toMap(MesPart::getPartNo, o -> new MesPartContext(o)));
    }

}
