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.apiservice.util.MesPcnException;
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.base.util.StringUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesPartShippingGroup;
import cn.estsh.i3plus.pojo.mes.bean.MesPartShippingGroupDetail;
import cn.estsh.i3plus.pojo.mes.bean.MesProduceSn;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkOrder;
import cn.estsh.i3plus.pojo.mes.bean.edi.cd.MesCimVolvoJisRackIdDetail;
import cn.estsh.i3plus.pojo.mes.bean.shipping.MesCustSortInfo;
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.*;
import cn.estsh.i3plus.pojo.mes.repository.edi.cd.MesCimVolvoJisRackIdDetailRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import groovy.util.logging.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
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 mesShippingCheckVolvoRackNoAndPartNoStrategyServiceImpl implements IMesShippingScanStrategyService {
    @Autowired
    private MesShippingOrderManagementRepository shippingOrderManagementRepository;
    @Autowired
    private MesShippingOrderManagementDetailRepository shippingOrderManagementDetailRepository;
    @Autowired
    private MesProduceSnRepository produceSnRepository;

    @Autowired
    private IMesProduceSnExtService produceSnExtService;

    @Autowired
    private MesCustomerPartRepository mesCustomerPartRepository;

    @Autowired
    private IMesConfigService mesConfigService;

    @Autowired
    private IMesPartShippingGroupService mesPartShippingGroupService;

    @Autowired
    private IMesShippingSnUniqueService mesShippingSnUniqueService;
    @Autowired
    private MesWorkOrderRepository workOrderRDao;
    @Autowired
    private MesCustSoftInfoRepository custSoftInfoRDao;
    @Autowired
    private MesCimVolvoJisRackIdDetailRepository rackIdDetailRDao;

    @Override
    public MesSortShippingCheckModel doScan(MesSortShippingCheckModel model, MesShippingOrderManagement orderManagement, MesPartShippingGroup shippingGroup) {
        //校验条码
        MesProduceSn produceSn = checkSn(model);
        MesWorkOrder workOrder = checkWorkOrder(model);
        if (!Objects.equals(workOrder.getPartNo(), produceSn.getPartNo())) {
            throw new ImppBusiException(String.format("产品条码物料【%s】与工单物料【%s】不一致，请检查数据！",  produceSn.getPartNo(), workOrder.getPartNo()));
        }
        boolean scanFlg = false;
        for (MesShippingOrderManagementDetail detail : model.getDetailList()) {
            if (detail.getPartNo().equals(produceSn.getPartNo()) && StringUtils.isEmpty(detail.getBarcode()) && !Objects.equals(detail.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)) {
                if (Objects.equals(detail.getVin(), workOrder.getVinCode())) {
                    throw new ImppBusiException(String.format("产品条码明细【%s】与发运单明细不匹配，请重新扫描！", model.getSn()));
                }
                checkDetailScanSeq(orderManagement, detail, workOrder);
                //校验发运明细
                checkShippingDetails(model, orderManagement, shippingGroup, produceSn, detail);
                scanFlg = true;
                //明细更新
                updateOrderManagementDetails(produceSn, orderManagement, detail, workOrder, model.getUserInfo());
                break;
            }
        }
        if (!scanFlg) {
            throw new ImppBusiException(String.format("【%s】此条码对应的【%s】物料号与发运单中物料号不匹配，请检查数据！", model.getSn(), produceSn.getPartNo()));
        }
        model.setMsg(String.format("条码【%s】扫描完成，请扫描下一个条码", model.getSn()));
        return model;
    }

    private void checkDetailScanSeq(MesShippingOrderManagement orderManagement, MesShippingOrderManagementDetail detail, MesWorkOrder workOrder) {
        if (StringUtils.isEmpty(workOrder.getWorkOrderSource())) {
            throw new ImppBusiException(String.format("工单【%s】缺少来源！", workOrder.getWorkOrderNo()));
        }
        MesCustSortInfo custSoftInfo = custSoftInfoRDao.getById(Long.parseLong(workOrder.getWorkOrderSource()));
        if (custSoftInfo == null || !Objects.equals(detail.getCustInfoSeq(), custSoftInfo.getCustInfoSeq())) {
            throw new ImppBusiException(String.format("发运单【%s】启用明细顺序防错，序号【%s】前还有未扫描的发运单明细，请检查数据！", orderManagement.getShippingCode(), custSoftInfo.getCustInfoSeq()));
        }
    }

    private void checkShippingDetails(MesSortShippingCheckModel model, MesShippingOrderManagement orderManagement, MesPartShippingGroup shippingGroup, MesProduceSn produceSn, MesShippingOrderManagementDetail detail) {


        //校验发运单明细顺序
        if (!Objects.isNull(shippingGroup) && !StringUtils.isEmpty(shippingGroup.getIsEnableShippingFailSafe()) && CommonEnumUtil.VALID == shippingGroup.getIsEnableShippingFailSafe()) {
            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()) && !Objects.isNull(MesExtEnumUtil.SHIPPING_GROUP_SCAN_CONFIRM_SEQ_MODE.valueOfDescription(orderManagement.getScanSeqWay()))) {
            //按照页面显示顺序校验
            Optional<MesShippingOrderManagementDetail> nextShippingDetail = model.getDetailList().stream().filter(k -> StringUtils.isEmpty(k.getBarcode()) && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).findFirst();
            if (nextShippingDetail.isPresent() && !StringUtils.isEmpty(nextShippingDetail.get().getPartTypeCode()) && !nextShippingDetail.get().getPartNo().equals(produceSn.getPartNo())) {
                throw new ImppBusiException(String.format("【%s】此条码扫描顺序错误，请检查数据！", model.getSn()));
            }
        }

        //校验客户零件信息是否存在 (默认需要验证, 值可能是[空/0/20])
        if (StringUtils.isEmpty(shippingGroup.getScanMethodJudgment()) || !shippingGroup.getScanMethodJudgment().equals(MesExtEnumUtil.SHIPPING_GROUP_SCAN_METHOD_JUDGMENT.PART_NO.getValueStr())) {
            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 MesWorkOrder checkWorkOrder(MesSortShippingCheckModel model) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getSn(), "custSn", packBean);
        MesWorkOrder workOrder = workOrderRDao.getByProperty(packBean);
        if (workOrder == null) {
            throw new ImppBusiException(String.format("客户条码【%s】对应的工单号不存在，请检查数据！", model.getSn()));
        }
        if (workOrder.getWorkOrderStatus() == MesExtEnumUtil.ORDER_STATUS.SHIPPING.getValue()) {
            throw new ImppBusiException(String.format("工单【%s】状态为已发运，请检查数据！", workOrder.getWorkOrderNo()));
        }
        if (workOrder.getWorkOrderStatus() == MesExtEnumUtil.ORDER_STATUS.RELEASE.getValue()) {
            throw new ImppBusiException(String.format("工单【%s】状态为已发布，请检查数据！", workOrder.getWorkOrderNo()));
        }
        if (workOrder.getWorkOrderStatus() != MesExtEnumUtil.ORDER_STATUS.PROCESS.getValue() &&
                workOrder.getWorkOrderStatus() != MesExtEnumUtil.ORDER_STATUS.COMPLETE.getValue() &&
                workOrder.getWorkOrderStatus() != MesExtEnumUtil.ORDER_STATUS.DISMANTLE.getValue()) {
            throw new ImppBusiException(String.format("工单【%s】状态为【%s】，请检查数据！", workOrder.getWorkOrderNo(), workOrder.getWorkOrderStatus()));
        }
        if (Objects.equals(workOrder.getOrderFlag(), MesExtEnumUtil.ORDER_TYPE_IDENTIFICATION.X.getValue())) {
            throw new ImppBusiException(String.format("工单【%s】的工单标识为空单，请检查数据！", workOrder.getWorkOrderNo()));
        }
        return workOrder;
    }

    private MesProduceSn checkSn(MesSortShippingCheckModel model) {
        //校验条码是否重复扫描 (不区分大小写)
        Optional<MesShippingOrderManagementDetail> optional = model.getDetailList().stream().filter(k -> !StringUtils.isEmpty(k.getBarcode()) && k.getBarcode().equalsIgnoreCase(model.getSn())).findFirst();
        if (optional.isPresent()) {
            throw new ImppBusiException(String.format("【%s】此条码已经扫描过，请检查数据！", model.getSn()));
        }
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getSn(), "productSn", packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{"createDatetime"}, packBean);
        MesProduceSn produceSn = produceSnRepository.getByProperty(packBean);
        if (!StringUtils.isEmpty(produceSn)) {
            //校验状态
            checkStatus(model, produceSn);
        } else {
            //外部条码解析
            MesShippingOrderManagementDetail mesShippingOrderManagementDetail = getMesShippingOrderManagementDetail(model);
            //封装信息
            produceSn = new MesProduceSn();
            produceSn.setSerialNumber(model.getSn());
            produceSn.setProductSn(model.getSn());
            produceSn.setPartNo(mesShippingOrderManagementDetail.getPartNo());
            produceSn.setOrganizeCode(model.getOrganizeCode());
        }
        return produceSn;
    }

    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()));
        }
        //校验产品质量状态 必须是状态为合格条码
        List<Integer> statusList = Stream.of(MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getValue(), MesExtEnumUtil.PRODUCE_QC_STATUS.SUSPICIOUS_TO_QUALIFIED.getValue()).collect(Collectors.toList());
        if (!statusList.contains(produceSn.getQcStatus())){
            throw new ImppBusiException(String.format("【%s】此条码质量状态为【%s】,请选择【%s】状态的条码，请检查数据！", model.getSn(), MesExtEnumUtil.PRODUCE_QC_STATUS.valueOfDescription(produceSn.getQcStatus()),
                    MesExtEnumUtil.PRODUCE_QC_STATUS.QUALIFIED.getDescription()));
        }
    }

    private MesShippingOrderManagementDetail getMesShippingOrderManagementDetail(MesSortShippingCheckModel model) {
        //外部解析条码长度卡控
        String cfgValue = mesConfigService.getCfgValue(model.getOrganizeCode(), MesPcnExtConstWords.MAX_SHIPPING_BARCODE_LENGTH);
        if (Integer.parseInt(cfgValue) < model.getSn().length()) {
            MesPcnException.throwMesBusiException("【%s】此条码长度超过【%s】位，请检查数据！", model.getSn(), cfgValue);
        }
        //唯一性校验
        if (mesShippingSnUniqueService.checkMesShippingSnUnique(model.getOrganizeCode(),model.getSn())) {
            throw new ImppBusiException(String.format("【%s】条码唯一性校验数据已存在，请检查数据！", model.getSn()));
        }
        //发运组代码不存在
        if (Objects.isNull(model.getMesPartShippingGroup())) {
            MesPcnException.throwMesBusiException("发运组信息不存在，请检查数据！");
        }
        List<MesShippingOrderManagementDetail> detailList = model.getDetailList().stream().filter(k -> !StringUtils.isEmpty(k.getCustPartNo()) && StringUtils.isEmpty(k.getBarcode()) && !Objects.equals(k.getIsScanFlg(), MesCommonConstant.TRUE_INTEGER)).collect(Collectors.toList());
        MesShippingOrderManagementDetail mesShippingOrderManagementDetail = null;
        for (MesShippingOrderManagementDetail managementDetail : detailList) {
            DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
            DdlPreparedPack.getStringEqualPack(managementDetail.getPartNo(), "erpPartNo", packBean);
            DdlPreparedPack.getStringEqualPack(managementDetail.getCustPartNo(), "custPartNo", packBean);
            if (checkMesPartShippingGroupDetailRule(model, managementDetail) && mesCustomerPartRepository.isExitByHql(packBean)) {
                mesShippingOrderManagementDetail = managementDetail;
                break;
            }
        }
        if (Objects.isNull(mesShippingOrderManagementDetail)) {
            throw new ImppBusiException(String.format("【%s】此条码未匹配到数据，请检查数据！", model.getSn()));
        }
        return mesShippingOrderManagementDetail;
    }

    private void updateOrderManagementDetails(MesProduceSn produceSn, MesShippingOrderManagement orderManagement, MesShippingOrderManagementDetail detail, MesWorkOrder workOrder, String userInfo) {
//        if (StringUtils.isEmpty(orderManagement.getCheckSeqCode())) {
            detail.setBarcode(produceSn.getProductSn());
            detail.setIsScanFlg(MesCommonConstant.TRUE_INTEGER);
            detail.setStatus(MesExtEnumUtil.SHIPPING_ORDER_DETAIL_SHIPPING_STATUS.SHIPPINGED.getValue());
            detail.setRemark("扫描完成");
            updateDetail(detail);
            orderManagement.setCheckSeqCode("1");
            update(orderManagement);

//            MesCustSortInfo custSoftInfo = custSoftInfoRDao.getById(Long.parseLong(workOrder.getWorkOrderSource()));
//            if (custSoftInfo != null) {
//                MesCimVolvoJisRackIdDetail rackIdDetail = rackIdDetailRDao.getById(custSoftInfo.getSourceId());
//                if (rackIdDetail != null) {
//                    detail.setPartPosition(rackIdDetail.getPosition());
//                }
//            }

            //根据是否启动记忆判断 若启用记忆，则根据保存数据库
            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.setActualQty(1);
                detail.setSystemSyncStatus(CommonEnumUtil.FALSE);
                detail.setVisualOrderNo(workOrder.getWorkOrderNo());
                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);
                }else{
                    //记录唯一性校验表
                    mesShippingSnUniqueService.insertMesShippingSnUnique(orderManagement.getOrganizeCode(),detail.getBarcode(),orderManagement.getShippingCode(),userInfo);
                }
            }
//        }
    }

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

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

    private Boolean checkMesPartShippingGroupDetailRule(MesSortShippingCheckModel model, MesShippingOrderManagementDetail managementDetail) {
        MesPartShippingGroupDetail mesPartShippingGroupDetail = mesPartShippingGroupService.getMesPartShippingGroupDetail(model.getOrganizeCode(), model.getMesPartShippingGroup().getShippingGroupCode(), managementDetail.getPartNo(), managementDetail.getCustPartNo());
        return !Objects.isNull(mesPartShippingGroupDetail) && !StringUtil.isEmpty(mesPartShippingGroupDetail.getSnRule()) && ((Boolean) ((IMesNumberRuleMatchDispatchService) SpringContextsUtil.getBean(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_20.getStrategyClass())).matchNumberRule(model.getOrganizeCode(), model.getSn(), mesPartShippingGroupDetail.getSnRule(), mesPartShippingGroupDetail.getSnRule()).get(MesPcnExtConstWords.RESULT));
    }
}
