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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.*;
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.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesProductionAssembly;
import cn.estsh.i3plus.pojo.mes.bean.MesProductionAssemblyUnique;
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.MesProductionAssemblyRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProductionAssemblyUniqueRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
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.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

/**
 * @Description : 保存装配记录工步 【非排序】
 * @Author : wangjie
 **/
@Slf4j
@Service("mesAssemblySaveStepService")
public class MesAssemblySaveStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

    @Autowired
    private MesProductionAssemblyRepository productionAssemblyRepository;

    @Autowired
    private MesProductionAssemblyUniqueRepository productionAssemblyUniqueRepository;

    @Autowired
    private IMesProduceSnExtService produceSnExtService;

    @Autowired
    private IMesStationContainerSnExtService stationContainerSnExtService;

    @Autowired
    private IMesRawSnWeightRecordService rawSnWeightRecordService;

    @Override
    public StepResult execute(StationRequestBean reqBean) {

        StationResultBean resultBean = new StationResultBean();

        StepResult stepResult = StepResult.getSuccessComplete();

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

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

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

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

        if (CollectionUtils.isEmpty(prodRuleContextList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "当前不存在非排序加工规则数据,请重置工序!");

        //判断是否存在装配件清单
        if (!checkIsNeedScanAssembly(prodRuleContextList)) {
            return stepDynamicsCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(), stepResult, true,
                    MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT, "当前加工规则无装配件清单,当前无需保存装配件记录!");
        }

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

        if (CollectionUtils.isEmpty(productionPsOutContextList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "当前不存在产出零件条码信息,请重置工序解决!");

        //获取上下文工位扫描监控信息
        MesScanMonitorContext scanMonitorContext = productionProcessContextStepService.dispatchScanMonitorContext(reqBean, true);

        //从上下文中取出工位当前要使用的设备
        MesCellEquipContext cellEquipContext = productionProcessContext.getCurCellEquip();

        Map<Integer, MesProductionPsOutContext> ppMap = CollectionUtils.isEmpty(productionPsOutContextList) ? null : productionPsOutContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()))).collect(Collectors.toMap(MesProductionPsOutContext::getForeignKey, o -> o));

        List<Long> productSnIdList = new ArrayList<>();

        //保存装配记录
        prodRuleContextList.stream().filter(o -> null != o).forEach(o -> saveProductionAssemblyData(reqBean, productSnIdList, productionProcessContext, o, ppMap, cellEquipContext, scanMonitorContext));

        if (!CollectionUtils.isEmpty(productSnIdList)) produceSnExtService.saveProduceSnList(reqBean, MesExtEnumUtil.PRODUCE_SN_STATUS.ASSEMBLY.getValue(), productSnIdList);

        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult, "保存装配记录成功!");

    }

    //判断是否存在装配件清单
    private Boolean checkIsNeedScanAssembly(List<MesProdRuleContext> prodRuleContextList) {
        Optional<MesProdRuleContext> optional = prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getAssemblyDataJson()))).findFirst();
        return (null == optional || !optional.isPresent()) ? false : true;
    }

    private void saveProductionAssemblyData(StationRequestBean reqBean, List<Long> productSnIdList, MesProductionProcessContext productionProcessContext, MesProdRuleContext prodRuleContext,
                                            Map<Integer, MesProductionPsOutContext> ppMap, MesCellEquipContext cellEquipContext, MesScanMonitorContext scanMonitorContext) {

        if (StringUtils.isEmpty(prodRuleContext.getAssemblyDataJson())) return;

        List<MesProductionAssemblyNosortContext> productionAssemblyNosortContextList = prodRuleContext.getNosortAssemblyDataContext();

        MesProductionPsOutContext productionPsOutContext = CollectionUtils.isEmpty(ppMap) ? null : ppMap.get(prodRuleContext.getForeignKey());

        for (MesProductionAssemblyNosortContext productionAssemblyNosortContext : productionAssemblyNosortContextList) {

            if (null == productionAssemblyNosortContext) continue;

            //容器匹配, 一个装配件信息可能对应多条原料条码
            if (productionAssemblyNosortContext.getMatchType().compareTo(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_80.getValue()) == 0) {
                insertMesProductionAssembly80(reqBean, productionProcessContext, cellEquipContext, prodRuleContext, productionPsOutContext, productionAssemblyNosortContext, scanMonitorContext, productSnIdList);
            } else if (productionAssemblyNosortContext.getMatchType().compareTo(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_90.getValue()) == 0) {
                insertMesProductionAssembly90(reqBean, productionProcessContext, cellEquipContext, prodRuleContext, productionPsOutContext, productionAssemblyNosortContext, scanMonitorContext, productSnIdList);
            } else {
                //一对一
                insertProductionAssembly(reqBean, productionProcessContext, cellEquipContext, prodRuleContext, productionPsOutContext, productionAssemblyNosortContext, scanMonitorContext, productSnIdList);
            }
        }
        //写入调配产出物重量记录
        rawSnWeightRecordService.insertOutPartNoWeightRecord(productionPsOutContext, productionAssemblyNosortContextList, reqBean.getOrganizeCode(), reqBean.getUserInfo());
    }

    //保存装配件绑定记录
    private void insertProductionAssembly(StationRequestBean reqBean, MesProductionProcessContext productionProcessContext, MesCellEquipContext cellEquipContext,
                                             MesProdRuleContext prodRuleContext, MesProductionPsOutContext productionPsOutContext,
                                             MesProductionAssemblyNosortContext productionAssemblyNosortContext, MesScanMonitorContext scanMonitorContext, List<Long> productSnIdList) {
        MesProductionAssembly productionAssembly = new MesProductionAssembly();
        BeanUtils.copyProperties(productionAssemblyNosortContext, productionAssembly);

        productionAssembly.setIsOrigSn(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());

        productionAssembly.setAreaCode(reqBean.getAreaCode());
        productionAssembly.setWorkCenterCode(reqBean.getWorkCenterCode());
        productionAssembly.setWorkCellCode(reqBean.getWorkCellCode());
        productionAssembly.setProcessCode(reqBean.getProcessCode());

        productionAssembly.setProcessName(productionProcessContext.getProcessName());
        productionAssembly.setCraftCode(productionProcessContext.getCraftCode());
        productionAssembly.setCraftName(productionProcessContext.getCraftName());

        productionAssembly.setEquipmentCode(cellEquipContext.getEquipmentCode());

        productionAssembly.setProductionRecordId(prodRuleContext.getProductionRecordId());
        productionAssembly.setMouldNo(prodRuleContext.getMouldNo());

        if (null != productionPsOutContext) {
            productionAssembly.setPartNo(productionPsOutContext.getPartNo());
            productionAssembly.setPartName(productionPsOutContext.getPartName());
            productionAssembly.setSerialNumber(productionPsOutContext.getSerialNumber());
            productionAssembly.setProductSn(productionPsOutContext.getProductSn());
            productionAssembly.setCustSn(productionPsOutContext.getCustSn());
        }

        if (null != scanMonitorContext) productionAssembly.setMouldRecordId(scanMonitorContext.getMouldRecordId());

        productionAssembly.setFid(UUID.randomUUID().toString());
        productionAssembly.setOrganizeCode(reqBean.getOrganizeCode());
        ConvertBean.serviceModelInitialize(productionAssembly, reqBean.getUserInfo());

        productionAssembly = productionAssemblyRepository.insert(productionAssembly);

        saveProductionAssemblyUnique(productionAssembly);

        if (!StringUtils.isEmpty(productionAssemblyNosortContext.getProductSnId())) productSnIdList.add(productionAssemblyNosortContext.getProductSnId());

        if (productionAssemblyNosortContext.getIsRepeat().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0 && productionAssemblyNosortContext.getIsRepeat2Cache().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) == 0)
            productionCustomContextStepService.dispatchRepeatAssemblySn(reqBean.getOrganizeCode(), reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), productionAssemblyNosortContext);
    }

    private void saveProductionAssemblyUnique(MesProductionAssembly productionAssembly) {
        if (!MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.checkUniqueRuleInDb(productionAssembly.getMatchType()) || StringUtils.isEmpty(productionAssembly.getAssemblySn())) return;
        MesProductionAssemblyUnique productionAssemblyUnique = new MesProductionAssemblyUnique();
        BeanUtils.copyProperties(productionAssembly, productionAssemblyUnique, MesPcnExtConstWords.ID);
        productionAssemblyUnique.setPid(productionAssembly.getId());
        productionAssemblyUniqueRepository.insert(productionAssemblyUnique);
    }

    //容器匹配, 一个装配件信息可能对应多条原料条码
    private void insertMesProductionAssembly80(StationRequestBean reqBean, MesProductionProcessContext productionProcessContext, MesCellEquipContext cellEquipContext,
                                               MesProdRuleContext prodRuleContext, MesProductionPsOutContext productionPsOutContext,
                                               MesProductionAssemblyNosortContext productionAssemblyNosortContext, MesScanMonitorContext scanMonitorContext, List<Long> productSnIdList) {
        //解析扣料信息
        List<MesContainerPackageDetailContext> containerPackageDetailContextList = StringUtils.isEmpty(productionAssemblyNosortContext.getContainerSnData()) ? null : JSONObject.parseArray(productionAssemblyNosortContext.getContainerSnData(), MesContainerPackageDetailContext.class);
        if (CollectionUtils.isEmpty(containerPackageDetailContextList)) return;

        for (MesContainerPackageDetailContext containerPackageDetailContext : containerPackageDetailContextList) {
            if (null == containerPackageDetailContext || StringUtils.isEmpty(containerPackageDetailContext.getBarCode())) continue;
            //覆盖原料条码字段跟工序用量
            productionAssemblyNosortContext.assemblySn(containerPackageDetailContext.getBarCode()).qty(containerPackageDetailContext.getDeductionQty());
            //保存装配件绑定记录
            insertProductionAssembly(reqBean, productionProcessContext, cellEquipContext, prodRuleContext, productionPsOutContext, productionAssemblyNosortContext, scanMonitorContext, productSnIdList);
            //写入扣料记录
            stationContainerSnExtService.insertContainerPackageDetailFeeding(reqBean, containerPackageDetailContext, productionPsOutContext);
            //修改上料明细表信息状态【扣减完成】
            if (MathOperation.compareTo(containerPackageDetailContext.getRemainQty(), new Double(0)) == 0) {
                stationContainerSnExtService.updateContainerPackageDetail(reqBean.getOrganizeCode(), reqBean.getUserInfo(), containerPackageDetailContext.getId(), MesExtEnumUtil.CONTAINER_BARCODE_STATUS.STATUS_20.getValue());
            }
        }

    }

    //调配原料, 记录原料的剩余数量及胶水总重量。
    private void insertMesProductionAssembly90(StationRequestBean reqBean, MesProductionProcessContext productionProcessContext, MesCellEquipContext cellEquipContext,
                                               MesProdRuleContext prodRuleContext, MesProductionPsOutContext productionPsOutContext,
                                               MesProductionAssemblyNosortContext productionAssemblyNosortContext, MesScanMonitorContext scanMonitorContext, List<Long> productSnIdList) {
        //保存装配件绑定记录
        insertProductionAssembly(reqBean, productionProcessContext, cellEquipContext, prodRuleContext, productionPsOutContext, productionAssemblyNosortContext, scanMonitorContext, productSnIdList);
        //写入调配原料剩余数量
        rawSnWeightRecordService.insertRawRemainWeightRecord(productionAssemblyNosortContext, reqBean.getOrganizeCode(), reqBean.getUserInfo());
    }
}
