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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProdRuleCfgExtService;
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.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.actor.shipping.dispatch.IFsmCommonService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.mes.pcn.util.PojoAttrUtil;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesProdRouteOptParam;
import cn.estsh.i3plus.pojo.mes.bean.MesProdRuleIgnoreCfg;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCell;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import cn.estsh.i3plus.pojo.mes.model.AttrBean;
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 cn.estsh.impp.framework.boot.util.SpringContextsUtil;
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.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("mesAssemblyShowSortStepService")
public class MesAssemblyShowSortStepService extends BaseStepService {

    @Autowired
    public IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    public IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    public IMesProdRuleCfgExtService prodRuleCfgExtService;

    @Autowired
    private IFsmCommonService fsmCommonService;

    @Override
    public StepResult execute(StationRequestBean reqBean) {

        StationResultBean resultBean = new StationResultBean();

        StepResult stepResult = StepResult.getSuccessComplete();

        //获取上下文信息: 处理加工不可用规则
        MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchProdRuleIgnoreCfgContext(reqBean);

        //配置错误 抛出异常
        if (!productionProcessContext.getSuccess()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

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

        //从上下文中取出生产线对象
        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();

        //从上下文中取出生产线对象
        MesCellEquipContext cellEquipContext = productionProcessContext.getCurCellEquip();

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

        //获取上下文进料零件条码信息集合
        List<MesProductionPsInContext> productionPsInContextList = productionDispatchContextStepService.getProductionPsInContext(reqBean);

        //上下文中不存在进料主条码数据信息
        if (CollectionUtils.isEmpty(productionPsInContextList) || CollectionUtils.isEmpty(productionPartContextList))
            stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), String.format("生产线[%s]工位[%s]当前已不存在加工单或条码数据信息,请重置工序!", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode()));

        //获取上下文产出零件条码信息集合
        List<MesProductionPsOutContext> productionPsOutContextList = productionDispatchContextStepService.getProductionPsOutContext(reqBean);

        //加工规则数据信息集合
        List<MesProdRuleContext> prodRuleContextList = new ArrayList<>();

        //封装排序加工规则
        doHandleProdRuleData(reqBean, resultBean, productionProcessContext, cellEquipContext, prodRuleContextList, productionPartContextList, productionPsInContextList, productionPsOutContextList);

        if (!CollectionUtils.isEmpty(prodRuleContextList)) {
            //获取上下文工位扫描监控信息
            MesScanMonitorContext scanMonitorContext = productionProcessContextStepService.dispatchScanMonitorContext(reqBean, true);
            //无需扫描的需要先写库, 使用isSaveDb=1 进行标记
            prodRuleContextList = ((MesAssemblySaveSortStepService) SpringContextsUtil.getBean("mesAssemblySaveSortStepService")).saveSortProductionAssembly(reqBean, prodRuleContextList, productionPsOutContextList, scanMonitorContext);

            //保存上下文产品加工规则信息集合
            productionDispatchContextStepService.dispatchProdRuleDataContext(reqBean, prodRuleContextList);
            //保存上下文产出零件信息
            if (!CollectionUtils.isEmpty(productionPartContextList)) productionDispatchContextStepService.dispatchProductionPartContext(reqBean, productionPartContextList);
            //保存进料主条码数据
            if (!CollectionUtils.isEmpty(productionPsInContextList)) productionDispatchContextStepService.dispatchProductionPsInContext(reqBean, productionPsInContextList);
            //保存产出条码数据
            if (!CollectionUtils.isEmpty(productionPsOutContextList)) productionDispatchContextStepService.dispatchProductionPsOutContext(reqBean, productionPsOutContextList);
        }

        //显示装配件信息
        Boolean isShow = showProductionAssembly(reqBean, resultBean, workCenter, prodRuleContextList);

        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult,
                isShow ? "已显示装配件清单,请查看!" : "当前腔匹配的加工规则无装配件清单!",
                MesPcnEnumUtil.PROMPT_SOUND.SUCCESS.getValue());

    }

    //获取装配件信息(子类进行重写)
    public MesProdRuleContext getProdRuleSortContext(StationRequestBean reqBean, MesProductionProcessContext productionProcessContext, MesCellEquipContext cellEquipContext, MesProductionPsInContext productionPsInContext,
                                                     Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap, Optional<Map<String, MesProdRouteOptParam>> stepParamMap) {
        MesProdRuleContext prodRuleContext = new MesProdRuleContext(
                reqBean.getOrganizeCode(), reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), reqBean.getProcessCode(), productionProcessContext.getCraftCode()).isCheckBindSeq(getIsCheckBindSeq(productionProcessContext.getWorkCell()))
                .equipmentCode(cellEquipContext.getEquipmentCode()).workOrderNo(productionPsInContext.getWorkOrderNo()).productSn(productionPsInContext.getProductSn()).foreignKey(productionPsInContext.getForeignKey());

        //是否剔除平行工位[工步参数]
        String isFilterParallel = (null != stepParamMap && stepParamMap.isPresent() && stepParamMap.get().containsKey(MesPcnExtConstWords.IS_FILTER_PARALLEL)) ? stepParamMap.get().get(MesPcnExtConstWords.IS_FILTER_PARALLEL).getParamValue() : null;
        return prodRuleCfgExtService.getProdRuleSortContext(prodRuleContext, prodRuleIgnoreCfgMap, isFilterCfg(isFilterParallel));
    }

    //判断是否按序扫描
    private Integer getIsCheckBindSeq(MesWorkCell workCell) {
        return (null != workCell && !StringUtils.isEmpty(workCell.getIsSeqScan())) ? workCell.getIsSeqScan() : CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue();
    }

    //装配件清单列表标题
    private List<AttrBean> dataAttrList(List<MesProdRuleContext> prodRuleContextList, Boolean isNeedShowCell, Boolean isNeedShowMatchRule) {
        List<AttrBean> attrBeanList = new ArrayList<>();
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.INDEX, "序号");
        if (isNeedShowCell) PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.WORK_CELL_CODE, "工位代码");
        if (isNeedShowMatchRule) PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.MATCH_TYPE_NAME, "装配方式");
        if (prodRuleContextList.size() > 1) {
            PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.WORK_ORDER_NO, "生产工单编号");
            PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.PART_NO, "产成零件编码");
        }
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.ASSEMBLY_PART_NO, "零件编码");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.ASSEMBLY_PART_NAME, "零件名称");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.ASSEMBLY_SN, "零件条码");
        PojoAttrUtil.loadPojoAttrs(attrBeanList, MesPcnExtConstWords.ASSEMBLY_STATUS_NAME, "装配状态");
        return attrBeanList;
    }

    //每个表格重新排序
    private List<MesAssemblyShowContext> sortAssemblyShowContextList(List<MesAssemblyShowContext> assemblyShowContextList) {
        return assemblyShowContextList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesAssemblyShowContext::getProcessSeq).thenComparing(MesAssemblyShowContext::getRouteSeq)).collect(Collectors.toList());
    }

    //查询排序线加工规则装配件数据信息
    private void doHandleProdRuleData(StationRequestBean reqBean, StationResultBean resultBean, MesProductionProcessContext productionProcessContext, MesCellEquipContext cellEquipContext,
                                      List<MesProdRuleContext> prodRuleContextList, List<MesProductionPartContext> productionPartContextList,
                                      List<MesProductionPsInContext> productionPsInContextList, List<MesProductionPsOutContext> productionPsOutContextList) {

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

        //获取加工不可用规则
        Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap = productionProcessContextStepService.getProdRuleIgnoreCfgContextMap(reqBean, productionProcessContext);

        //拿到当前最大的foreignKey
        Optional<MesProductionPsInContext> maxForeignKeyOptional = productionPsInContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()))).max(Comparator.comparing(MesProductionPsInContext::getForeignKey));
        Integer foreignKey = (null != maxForeignKeyOptional && maxForeignKeyOptional.isPresent()) ? maxForeignKeyOptional.get().getForeignKey() : MesPcnExtConstWords.ZERO;

        for (MesProductionPsInContext productionPsInContext : productionPsInContextList) {

            //foreignKey有值代表已经匹配过产品加工规则
            if (null == productionPsInContext || productionPsInContext.getIsFinishCode().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0 || !StringUtils.isEmpty(productionPsInContext.getForeignKey())) continue;

            //【排序线】获取产品加工规则(条码对应的装配件绑定记录,目前条码等同工单)
            productionPartContextList.stream().filter(o -> (null != o && o.getWorkOrderNo().equals(productionPsInContext.getWorkOrderNo()))).findFirst().get().foreignKey(productionPsInContext.foreignKey(foreignKey += 1).getForeignKey());
            productionPsOutContextList.stream().filter(o -> (null != o && o.getWorkOrderNo().equals(productionPsInContext.getWorkOrderNo()))).findFirst().get().foreignKey(productionPsInContext.getForeignKey());

            //获取装配件信息
            MesProdRuleContext prodRuleContext = getProdRuleSortContext(reqBean, productionProcessContext, cellEquipContext, productionPsInContext, prodRuleIgnoreCfgMap, stepParamMap);
            prodRuleContextList.add(prodRuleContext);

            //标记平行工位数据为无效
            if (!StringUtils.isEmpty(prodRuleContext.getParallelInfo())) {
                ((MesAssemblySaveSortStepService) SpringContextsUtil.getBean("mesAssemblySaveSortStepService")).deleteSortWorkOrderAssembly(reqBean, prodRuleContext);
            }

        }

    }

    //显示装配件信息(子类进行重写)
    public Boolean showProductionAssembly(StationRequestBean reqBean, StationResultBean resultBean, MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList) {
        return showProductionAssembly(reqBean, resultBean, workCenter, prodRuleContextList, false, false);
    }

    //显示或者匹配装配件信息 公共调用
    public Boolean showProductionAssembly(StationRequestBean reqBean, StationResultBean resultBean, MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList, Boolean isNeedCheckShowCell, Boolean isNeedCalcTop) {

        //用于获取前端置顶ID
        List<MesProductionAssemblySortContext> allAssemblyList = null;

        //验证是否需要显示工位代码列
        Boolean isNeedShowCell = false;
        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {

            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getAssemblyDataJson())) continue;

            List<MesProductionAssemblySortContext> productionAssemblySortContextList = prodRuleContext.getSortAssemblyDataContext();

            //存在其他工位的装配件的时候需要显示出工位代码列
            if (isNeedCheckShowCell && !isNeedShowCell && !productionAssemblySortContextList.get(0).getWorkCellCode().equals(reqBean.getWorkCellCode())) isNeedShowCell = true;

            if (isNeedCalcTop) {
                if (CollectionUtils.isEmpty(allAssemblyList)) allAssemblyList = new ArrayList<>();
                allAssemblyList.addAll(productionAssemblySortContextList);
            }

        }

        //获取前端置顶信息 【sourceId&MatchDatetime】
        String topRowInfo = getTopRowInfo(allAssemblyList);

        //装配件显示规则配置
        Boolean isNeedShowMatchRule = checkIsNeedShowMatchRule(reqBean);

        //列名集合
        List<AttrBean> attrBeanList = null;

        for (MesProdRuleContext prodRuleContext : prodRuleContextList) {

            if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getAssemblyDataJson())) continue;

            //封装匹配当前设备的装配件信息
            List<MesAssemblyShowContext> assemblyShowContextList = getAssemblyShowContextList(prodRuleContext.getSortAssemblyDataContext(), isNeedShowMatchRule, topRowInfo);
            if (CollectionUtils.isEmpty(assemblyShowContextList)) continue;

            //装配件清单列表标题
            if (CollectionUtils.isEmpty(attrBeanList)) attrBeanList = dataAttrList(prodRuleContextList, isNeedShowCell, isNeedShowMatchRule);

            //封装多表格
            resultBean.addStationResultBeans(new StationResultBean().dataType(MesPcnEnumUtil.STATION_DATA_TYPE.TABLE.getValue()).dataAttrList(attrBeanList).resultList(assemblyShowContextList));

        }

        if (CollectionUtils.isEmpty(resultBean.getStationResultBeans())) return false;

        resultBean.busiType(MesPcnEnumUtil.STATION_BUSI_TYPE.STEP_CUSTOM_CONTENT.getValue()).dataType(MesPcnEnumUtil.STATION_DATA_TYPE.TABLES.getValue());
        this.sendMessage(reqBean, resultBean);

        return true;

    }

    //获取前端置顶信息 【sourceId&MatchDatetime】
    private String getTopRowInfo(List<MesProductionAssemblySortContext> allAssemblyList) {
        if (CollectionUtils.isEmpty(allAssemblyList)) return null;
        allAssemblyList = allAssemblyList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getMatchDatetime()))).sorted(Comparator.comparing(MesProductionAssemblySortContext::getMatchDatetime).reversed()).collect(Collectors.toList());
        return CollectionUtils.isEmpty(allAssemblyList) ? null : new StringJoiner(MesPcnExtConstWords.AND).add(allAssemblyList.get(0).getSourceId().toString()).add(allAssemblyList.get(0).getMatchDatetime()).toString();
    }

    //装配件显示规则配置【工位参数】
    private Boolean checkIsNeedShowMatchRule(StationRequestBean reqBean) {
        return fsmCommonService.checkWcpcMapIsMatchTrue(reqBean, MesPcnExtConstWords.ASSEMBLY_SHOW_MR_CFG);
    }

    //封装匹配当前设备的装配件信息
    private List<MesAssemblyShowContext> getAssemblyShowContextList(List<MesProductionAssemblySortContext> productionAssemblySortContextList, Boolean isNeedShowMatchRule, String topRowInfo) {
        if (CollectionUtils.isEmpty(productionAssemblySortContextList)) return null;
        List<MesAssemblyShowContext> assemblyShowContextList = new ArrayList<>();
        for (MesProductionAssemblySortContext item : productionAssemblySortContextList) {
            //不显示且不扫描/仅目视的不显示出来, 已经存在于DB的不显示出来
            if (null == item || item.getIsExistDb().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0 || MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.checkIsNoShow(item.getMatchType())) continue;
            assemblyShowContextList.add(assemblyShowContext(item, isNeedShowMatchRule, topRowInfo));
        }

        assemblyShowContextList = sortAssemblyShowContextList(assemblyShowContextList);

        AtomicReference<Integer> index = new AtomicReference<>(0);
        assemblyShowContextList.forEach(o -> o.index(index.updateAndGet(v -> v + 1)));

        return assemblyShowContextList;
    }

    //封装装配件信息
    private MesAssemblyShowContext assemblyShowContext(MesProductionAssemblySortContext productionAssemblyContext, Boolean isNeedShowMatchRule, String topRowInfo) {
        MesAssemblyShowContext assemblyShowContext = new MesAssemblyShowContext();
        BeanUtils.copyProperties(productionAssemblyContext, assemblyShowContext);
        overrideAssemblyPartName(productionAssemblyContext, assemblyShowContext);
        if (isNeedShowMatchRule) assemblyShowContext.setMatchTypeName(showMatchRule(assemblyShowContext));
        assemblyShowContext.setAssemblyStatusName(MesExtEnumUtil.ASSEMBLY_STATUS.valueOfDescription(assemblyShowContext.getAssemblyStatus()));
        if (MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue() != assemblyShowContext.getAssemblyStatus())
            assemblyShowContext.setColor(StringUtils.isEmpty(assemblyShowContext.getShowColor()) ? MesExtEnumUtil.COLOR.GREEN.getValue() : assemblyShowContext.getShowColor());
        if (!StringUtils.isEmpty(topRowInfo) && !StringUtils.isEmpty(productionAssemblyContext.getSourceId()) && !StringUtils.isEmpty(productionAssemblyContext.getMatchDatetime()) &&
                topRowInfo.equals(new StringJoiner(MesPcnExtConstWords.AND).add(productionAssemblyContext.getSourceId().toString()).add(productionAssemblyContext.getMatchDatetime()).toString())) assemblyShowContext.isTop();

        return assemblyShowContext;
    }

    //显示规则
    private MesAssemblyShowContext overrideAssemblyPartName(MesProductionAssemblySortContext productionAssemblyContext, MesAssemblyShowContext assemblyShowContext) {
        if (StringUtils.isEmpty(productionAssemblyContext.getDisplayRule())) return assemblyShowContext;
        if (productionAssemblyContext.getDisplayRule().compareTo(MesExtEnumUtil.DISPLAY_RULE.DISPLAY_RULE_10.getValue()) == 0) return assemblyShowContext;
        if (productionAssemblyContext.getDisplayRule().compareTo(MesExtEnumUtil.DISPLAY_RULE.DISPLAY_RULE_20.getValue()) == 0) return assemblyShowContext.assemblyPartName(productionAssemblyContext.getActionName());
        if (StringUtils.isEmpty(productionAssemblyContext.getActionName())) return assemblyShowContext;
        return assemblyShowContext.assemblyPartName(assemblyShowContext.getAssemblyPartName() + MesPcnExtConstWords.SQUARE_BRACKETS_L + productionAssemblyContext.getActionName() + MesPcnExtConstWords.SQUARE_BRACKETS_R);
    }

    private String showMatchRule(MesAssemblyShowContext assemblyShowContext) {
        if (!MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.checkIsNeedShowMatchRule(assemblyShowContext.getMatchType())) return MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.valueOfDescription(assemblyShowContext.getMatchType());
        return MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.valueOfDescription(assemblyShowContext.getMatchType()) + "【" + assemblyShowContext.getMatchRule() + "】";
    }

    //判断配置设置是否过滤数据的标志
    public Boolean isFilterCfg(String isFilterCfg) {
        return StringUtils.isEmpty(isFilterCfg) ? false : true;
    }

}
