package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.shippingscan.strategy;

import cn.estsh.i3plus.ext.mes.pcn.api.busi.*;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.aspect.MonitorLog;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.busi.shippingscan.IMesShippingScanStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.constant.MesCommonConstant;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesSortShippingCheckModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesConfig;
import cn.estsh.i3plus.pojo.mes.bean.MesPartShippingGroup;
import cn.estsh.i3plus.pojo.mes.bean.MesProduceSn;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkOrder;
import cn.estsh.i3plus.pojo.mes.bean.shipping.MesShippingOrderManagement;
import cn.estsh.i3plus.pojo.mes.bean.shipping.MesShippingOrderManagementDetail;
import cn.estsh.i3plus.pojo.mes.repository.MesCustomerPartRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProduceSnRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesShippingOrderManagementDetailRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesShippingOrderManagementRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import groovy.util.logging.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.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description : 扫描条码和目视单
 * @Reference :
 * @Author : junsheng.li
 * @CreateDate 2024/9/25 10:54
 * @Modify:
 **/
@Service
@Slf4j
public class MesShippingScanSnAndOrderStrategyServiceImpl implements IMesShippingScanStrategyService {
    @Autowired
    private MesShippingOrderManagementRepository shippingOrderManagementRepository;

    @Autowired
    private MesShippingOrderManagementDetailRepository shippingOrderManagementDetailRepository;

    @Autowired
    private MesProduceSnRepository produceSnRepository;

    @Autowired
    private IMesProduceSnExtService produceSnExtService;

    @Autowired
    private MesCustomerPartRepository mesCustomerPartRepository;

    @Autowired
    private IMesWorkOrderExtService mesWorkOrderExtService;

    @Autowired
    private IMesEmergencyLocationService mesEmergencyLocationService;

    @Autowired
    private IMesCustomerSnTransformService mesCustomerSnTransformService;

    @Autowired
    private IMesConfigService mesConfigService;

    @Override
    public MesSortShippingCheckModel doScan(MesSortShippingCheckModel model, MesShippingOrderManagement orderManagement, MesPartShippingGroup shippingGroup) {
        final String barcode = mesCustomerSnTransformService.transformBarCodeGm(model.getSn());
        if (!Objects.isNull(model.getLastShippingDetailId())) {
            //更新单据信息
            model.getDetailList().stream().filter(t -> t.getId().equals(model.getLastShippingDetailId())).forEach(detail -> {
                //第一次扫描的是条码
                if (StringUtils.isEmpty(detail.getVisualOrderNo())) {
                    //校验目视单是否已经扫描
                    checkVisualOrderNoIsScan(model);
                    detail.setVisualOrderNo(barcode);
                    model.setSn(detail.getBarcode());
                    model.setMsg(String.format("条码【%s】扫描成功，请扫描下一个目视单",model.getSn()));
                } else {
                    //校验条码是否已经扫描
                    checkIsScan(model);
                    detail.setBarcode(barcode);
                    model.setMsg(String.format("目视单【%s】扫描成功，请扫描下一个条码",model.getSn()));
                }
                MesProduceSn produceSn = checkSn(model);
                updateOrderManagementDetails(orderManagement, detail, getMesWorkOrder(model, produceSn, detail), produceSn, model.getUserInfo());
            });
            model.setLastShippingDetailId(null);
        } else {
            //查询工单
            MesWorkOrder workOrder = mesWorkOrderExtService.getWorkOrder(model.getOrganizeCode(), barcode);
            //扫描的工单或条码对应的零件
            String partNo = getPartNo(model, workOrder);
            boolean scanFlg = false;
            for (MesShippingOrderManagementDetail detail : model.getDetailList()) {
                if (detail.getCustPartNo().equals(partNo) && StringUtils.isEmpty(detail.getBarcode()) && !Objects.equals(detail.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)) {
                    //校验发运明细
                    checkShippingDetails(model, orderManagement, shippingGroup, partNo, detail);
                    detail.setBarcode(barcode);
                    //如果第一次扫描的是目视单,先缓存数据用于第二次校验
                    if(!Objects.isNull(workOrder)){
                        detail.setVisualOrderNo(barcode);
                    }
                    //校验通过的明细ID
                    model.setLastShippingDetailId(detail.getId());
                    scanFlg = true;
                    break;
                }
            }
            if (!scanFlg) {
                throw new ImppBusiException(String.format("【%s】此目视单对应的【%s】物料号与发运单中物料号不匹配，请检查数据！", model.getSn(), partNo));
            }
            //提示信息
            if(Objects.isNull(workOrder)){
                model.setMsg(String.format("条码【%s】扫描成功，请扫描目视单",model.getSn()));
            }else{
                model.setMsg(String.format("目视单【%s】扫描成功，请扫描条码",model.getSn()));
            }
        }

        return model;
    }

    private String getPartNo(MesSortShippingCheckModel model, MesWorkOrder workOrder) {
        if (Objects.isNull(workOrder)) {
            //校验条码是否已经扫描
            checkIsScan(model);
            //如果扫描的是条码，校验条码
            return checkSn(model).getCustPartNo();
        }else{
            //校验目视单是否已经扫描
            checkVisualOrderNoIsScan(model);
            //校验目视单状态
            if (MesExtEnumUtil.ORDER_STATUS.COMPLETE.getValue() != workOrder.getWorkOrderStatus() || MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue() != workOrder.getQcStatus()) {
                throw new ImppBusiException(String.format("目视单【%s】状态为【%s】质量状态为【%s】，不允许发运！请检查数据！", model.getSn(), MesExtEnumUtil.ORDER_STATUS.valueOfDescription(workOrder.getWorkOrderStatus()), MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(workOrder.getQcStatus())));
            }
            return workOrder.getCustPartNo();
        }
    }

    private MesWorkOrder getMesWorkOrder(MesSortShippingCheckModel model, MesProduceSn produceSn, MesShippingOrderManagementDetail detail) {
        MesWorkOrder workOrder = mesWorkOrderExtService.getWorkOrder(model.getOrganizeCode(), detail.getVisualOrderNo());
        if (Objects.isNull(workOrder)) {
            throw new ImppBusiException(String.format("目视单【%s】不存在，请检查数据！", detail.getVisualOrderNo()));
        }
        //校验目视单状态
        if (MesExtEnumUtil.ORDER_STATUS.COMPLETE.getValue() != workOrder.getWorkOrderStatus() || MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue() != workOrder.getQcStatus()) {
            throw new ImppBusiException(String.format("目视单【%s】状态为【%s】质量状态为【%s】，不允许发运！请检查数据！", detail.getVisualOrderNo(), MesExtEnumUtil.ORDER_STATUS.valueOfDescription(workOrder.getWorkOrderStatus()), MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(workOrder.getQcStatus())));
        }
        //校验条码是否匹配
        if (!Objects.equals(produceSn.getCustSn(), workOrder.getCustSn())) {
            throw new ImppBusiException(String.format("目视单【%s】条码【%s】与扫描条码【%s】，不匹配！请检查数据！", detail.getVisualOrderNo(), workOrder.getCustSn(), produceSn.getCustSn()));
        }
        //校验零件是否匹配
        if (!Objects.equals(produceSn.getCustPartNo(), workOrder.getCustPartNo())) {
            throw new ImppBusiException(String.format("目视单【%s】零件【%s】与发运单零件【%s】，不匹配！请检查数据！", detail.getVisualOrderNo(), workOrder.getCustPartNo(), detail.getCustPartNo()));
        }
        return workOrder;
    }

    private void checkShippingDetails(MesSortShippingCheckModel model, MesShippingOrderManagement orderManagement, MesPartShippingGroup shippingGroup, String partNo, MesShippingOrderManagementDetail detail) {
        //校验发运单明细顺序
        if (!Objects.isNull(shippingGroup) && !StringUtils.isEmpty(shippingGroup.getIsEnableShippingFailSafe()) && CommonEnumUtil.VALID == shippingGroup.getIsEnableShippingFailSafe()) {
            //45550 PDA-MES-PDA发运扫描排序方式修改
            List<MesConfig> shippingBusiSoftCfgList = mesConfigService.getConfigList(orderManagement.getOrganizeCode(),
                    MesCommonConstant.SHIPPING_BUSI_SOFT_CFG, shippingGroup.getShippingGroupCode(), null);
            if (CollectionUtils.isEmpty(shippingBusiSoftCfgList)) {
                Optional<MesShippingOrderManagementDetail> first = model.getDetailList().stream().filter(k -> k.getCustInfoSeq().compareTo(detail.getCustInfoSeq()) < 0 && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst();
                if (first.isPresent()) {
                    throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错，序号【%s】前还有未扫描的发运单明细，请检查数据！", orderManagement.getShippingCode(), detail.getCustInfoSeq()));
                }
            }else {
                MesConfig mesConfig = shippingBusiSoftCfgList.get(0);
                if (!Objects.isNull(mesConfig) &&
                        !StringUtils.isEmpty(mesConfig.getCfgValue()) &&
                        "logic_seq".equals(mesConfig.getCfgValue())) {
                    Optional<MesShippingOrderManagementDetail> first = model.getDetailList().stream().filter(k -> k.getLogicSeq().compareTo(detail.getLogicSeq()) < 0 && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst();
                    if (first.isPresent()) {
                        throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错，序号【%s】前还有未扫描的发运单明细，请检查数据！", orderManagement.getShippingCode(), detail.getLogicSeq()));
                    }
                }else {
                    Optional<MesShippingOrderManagementDetail> first = model.getDetailList().stream().filter(k -> k.getCustInfoSeq().compareTo(detail.getCustInfoSeq()) < 0 && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst();
                    if (first.isPresent()) {
                        throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错，序号【%s】前还有未扫描的发运单明细，请检查数据！", orderManagement.getShippingCode(), detail.getCustInfoSeq()));
                    }
                }
            }
        }
        //判断是否需要排序校验 默认排序则需要校验
        if (!StringUtils.isEmpty(orderManagement.getScanSeqWay()) && orderManagement.getScanSeqWay() == MesExtEnumUtil.SHIPPING_GROUP_SCAN_CONFIRM_SEQ_MODE.SHIPPING_GROUP_SCAN_CONFIRM_SEQ_MODE_10.getValue()) {
            //获取明细中最小的
            Optional<String> minPartNo = model.getDetailList().stream().filter(k -> StringUtils.isEmpty(k.getBarcode()) && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER))
                    .min(Comparator.comparingLong(MesShippingOrderManagementDetail::getCustInfoSeq)).map(MesShippingOrderManagementDetail::getCustPartNo);
            //若扫描的不是最小顺序 则报错
            if (minPartNo.isPresent() && !minPartNo.get().equals(partNo)) {
                throw new ImppBusiException(String.format("【%s】此条码扫描顺序错误，请检查数据！", model.getSn()));
            }
        }
        //校验客户零件信息是否存在
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(detail.getPartNo(), "erpPartNo", packBean);
        DdlPreparedPack.getStringEqualPack(detail.getCustPartNo(), "custPartNo", packBean);
        if (!mesCustomerPartRepository.isExitByHql(packBean)) {
            throw new ImppBusiException(String.format("零件号【%s】客户零件号【%s】关系不存在，请检查数据！", detail.getPartNo(), detail.getCustPartNo()));
        }
    }

    private void checkVisualOrderNoIsScan(MesSortShippingCheckModel model){
        //校验目视单是否已经扫描
        if (model.getDetailList().stream().anyMatch(t -> !StringUtils.isEmpty(t.getVisualOrderNo()) && t.getVisualOrderNo().contains(model.getSn()))) {
            throw new ImppBusiException(String.format("【%s】此目视单已经扫描过，请检查数据！", model.getSn()));
        }
    }

    private void checkIsScan(MesSortShippingCheckModel model){
        //校验条码是否重复扫描
        Optional<MesShippingOrderManagementDetail> optional = model.getDetailList().stream().filter(k -> !StringUtils.isEmpty(k.getBarcode()) && k.getBarcode().contains(model.getSn())).findFirst();
        if (optional.isPresent()) {
            throw new ImppBusiException(String.format("【%s】此条码已经扫描过，请检查数据！", model.getSn()));
        }
    }

    private MesProduceSn checkSn(MesSortShippingCheckModel model) {
        MesProduceSn produceSn = getMesProduceSn(model.getOrganizeCode(), model.getSn());
        if (StringUtils.isEmpty(produceSn)) {
            throw new ImppBusiException(String.format("【%s】此条码不存在，请检查数据！", model.getSn()));
        }
        //校验状态
        checkStatus(model, produceSn);
        return produceSn;
    }

    private MesProduceSn getMesProduceSn(String organizeCode, String productSn) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(productSn, "custSn", packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{"createDatetime"}, packBean);
        return produceSnRepository.getByProperty(packBean);
    }

    private void checkStatus(MesSortShippingCheckModel model, MesProduceSn produceSn) {
        //校验产品条码状态 必须是状态为已下线条码
        if (produceSn.getSnStatus() != MesExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue() && produceSn.getSnStatus() != MesExtEnumUtil.PRODUCE_SN_STATUS.CREATE.getValue()) {
            throw new ImppBusiException(String.format("【%s】此条码状态为【%s】,请选择状态为【%s】或【%s】状态的条码，请检查数据！", model.getSn(), MesExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSn.getSnStatus()),
                    MesExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getDescription(), MesExtEnumUtil.PRODUCE_SN_STATUS.CREATE.getDescription()));
        }
        //校验产品质量状态 必须是状态为合格条码
        if (produceSn.getQcStatus() != MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue()) {
            throw new ImppBusiException(String.format("【%s】此条码质量状态为【%s】,请选择【%s】状态的条码，请检查数据！", model.getSn(), MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSn.getQcStatus()),
                    MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getDescription()));
        }
    }

    private void updateOrderManagementDetails(MesShippingOrderManagement orderManagement, MesShippingOrderManagementDetail detail, MesWorkOrder workOrder,MesProduceSn produceSn, String userInfo) {
        if (StringUtils.isEmpty(orderManagement.getCheckSeqCode())) {
            detail.setIsScanFlg(MesCommonConstant.TRUE_INTEGER);
            detail.setStatus(MesExtEnumUtil.SHIPPING_ORDER_DETAIL_SHIPPING_STATUS.SHIPPINGED.getValue());
            detail.setRemark("扫描完成");
            //根据是否启动记忆判断 若启用记忆，则根据保存数据库
            if (!StringUtils.isEmpty(orderManagement.getIsEnableMemory()) && Objects.equals(orderManagement.getIsEnableMemory(), MesCommonConstant.TRUE_INTEGER)) {
                //若发运单状态为创建或发布 则写入开始扫描时间
                if (!StringUtils.isEmpty(orderManagement.getStatus()) && (orderManagement.getStatus() == MesExtEnumUtil.SHIPPING_ORDER_STATUS.CREATE.getValue() ||
                        orderManagement.getStatus() == MesExtEnumUtil.SHIPPING_ORDER_STATUS.PUBLISHED.getValue())) {
                    orderManagement.setStartScanTime(TimeTool.getNowTime(true));
                }

                orderManagement.setStatus(MesExtEnumUtil.SHIPPING_ORDER_STATUS.SHIPPING.getValue());
                orderManagement.setSystemSyncStatus(CommonEnumUtil.FALSE);
                ConvertBean.serviceModelUpdate(orderManagement, userInfo);
                update(orderManagement);
                //条码格式(扫描目视单,扫描条码)
                detail.setBarcode(new StringJoiner(MesPcnExtConstWords.COMMA).add(detail.getVisualOrderNo()).add(detail.getBarcode()).toString());
                detail.setActualQty(MesPcnExtConstWords.ONE);
                detail.setSystemSyncStatus(CommonEnumUtil.FALSE);
                ConvertBean.serviceModelUpdate(detail, userInfo);
                updateDetail(detail);
                //内部条码更新条码状态
                if (!Objects.isNull(produceSn.getId())) {
                    produceSn.setSnStatus(MesExtEnumUtil.PRODUCE_SN_STATUS.SHIPPED.getValue());
                    produceSn.setSystemSyncStatus(CommonEnumUtil.FALSE);
                    ConvertBean.serviceModelUpdate(produceSn, userInfo);
                    produceSnExtService.update(produceSn);
                }
                //更新工单状态为发运
                mesWorkOrderExtService.updateMesWorkOrderOrderStatusShippingByWorkOrderNo(orderManagement.getOrganizeCode(), Stream.of(workOrder.getWorkOrderNo()).collect(Collectors.toList()), userInfo);
                //更新应急件库位管理库存出库
                mesEmergencyLocationService.doShippingStockOutOnline(orderManagement.getOrganizeCode(), detail.getVisualOrderNo(), userInfo, true);
            }
        }
    }


    @MonitorLog
    public void update(MesShippingOrderManagement item) {
        shippingOrderManagementRepository.update(item);
    }

    @MonitorLog
    public void updateDetail(MesShippingOrderManagementDetail item) {
        shippingOrderManagementDetailRepository.update(item);
    }

}
