package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.shkj.common.annotation.DataScopeConsignor;
import com.shkj.common.constant.HttpStatus;
import com.shkj.common.core.domain.Result;
import com.shkj.common.enums.IsDelEnum;
import com.shkj.common.utils.SecurityUtils;
import com.shkj.common.utils.StringUtils;
import com.shkj.system.service.ISysParameterService;
import com.shkj.wms.bo.*;
import com.shkj.wms.constants.ParameterConstants;
import com.shkj.wms.domain.*;
import com.shkj.wms.mapper.BaseLocationMapper;
import com.shkj.wms.service.*;
import com.shkj.wms.config.ValidList;
import com.shkj.wms.enums.DeleteFlagEnum;
import com.shkj.wms.utils.BeanMapperUtils;
import com.shkj.wms.utils.JsonUtil;
import com.shkj.wms.utils.TunnelTaskUtil;
import com.shkj.wms.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 货位资料Service业务层处理
 *
 * @author lch
 * @date 2022-04-23
 */
@Slf4j
@Service
public class BaseLocationServiceImpl extends ServiceImpl<BaseLocationMapper, BaseLocation> implements IBaseLocationService {

    @Autowired
    private ISysBatchService sysBatchService;

    @Autowired
    private IBaseAreaService iBaseAreaService;

    @Autowired
    private ISysStockDetailService iSysStockDetailService;

    @Resource
    private TunnelTaskUtil tunnelTaskUtil;

    @Resource
    ISysParameterService sysParameterService;

    @Resource
    BaseLocationMapper baseLocationMapper;

    @Autowired
    private IBaseDeriveService baseDeriveService;

    @Override
    public Result<BaseLocationVo> queryById(Long id) {
        BaseLocation db = this.baseMapper.selectById(id);
        BaseLocationVo vo = BeanUtil.toBean(db, BaseLocationVo.class);
        return Result.ok().data(vo);
    }

    @Override
    public List<BaseLocationVo> queryList(BaseLocationQueryBo bo) {
        LambdaQueryWrapper<BaseLocation> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(bo.getLocationCode()), BaseLocation::getLocationCode, bo.getLocationCode());
        lqw.like(StrUtil.isNotBlank(bo.getLocationName()), BaseLocation::getLocationName, bo.getLocationName());
        lqw.eq(bo.getAreaId() != null, BaseLocation::getAreaId, bo.getAreaId());
        lqw.eq(StrUtil.isNotBlank(bo.getType()), BaseLocation::getType, bo.getType());
        lqw.eq(StrUtil.isNotBlank(bo.getTunnel()), BaseLocation::getTunnel, bo.getTunnel());
        lqw.eq(StrUtil.isNotBlank(bo.getLocationRow()), BaseLocation::getLocationRow, bo.getLocationRow());
        lqw.eq(StrUtil.isNotBlank(bo.getLayer()), BaseLocation::getLayer, bo.getLayer());
        lqw.eq(StrUtil.isNotBlank(bo.getLocationColumn()), BaseLocation::getLocationColumn, bo.getLocationColumn());
        lqw.eq(StrUtil.isNotBlank(bo.getIsuse()), BaseLocation::getIsuse, bo.getIsuse());
        lqw.eq(bo.getLength() != null, BaseLocation::getLength, bo.getLength());
        lqw.eq(bo.getWidth() != null, BaseLocation::getWidth, bo.getWidth());
        lqw.eq(bo.getHeight() != null, BaseLocation::getHeight, bo.getHeight());
        lqw.eq(bo.getVolume() != null, BaseLocation::getVolume, bo.getVolume());
        lqw.eq(bo.getWeight() != null, BaseLocation::getWeight, bo.getWeight());
        lqw.eq(bo.getCapacity() != null, BaseLocation::getCapacity, bo.getCapacity());
        lqw.eq(bo.getSkunum() != null, BaseLocation::getSkunum, bo.getSkunum());
        lqw.eq(StrUtil.isNotBlank(bo.getLocationGroup()), BaseLocation::getLocationGroup, bo.getLocationGroup());
        lqw.eq(StrUtil.isNotBlank(bo.getLogicArea()), BaseLocation::getLogicArea, bo.getLogicArea());
        lqw.eq(StrUtil.isNotBlank(bo.getAbcClassify()), BaseLocation::getAbcClassify, bo.getAbcClassify());
        lqw.eq(StrUtil.isNotBlank(bo.getFloor()), BaseLocation::getFloor, bo.getFloor());
        lqw.eq(StrUtil.isNotBlank(bo.getStorageConditions()), BaseLocation::getStorageConditions, bo.getStorageConditions());
        lqw.eq(StrUtil.isNotBlank(bo.getRoute()), BaseLocation::getRoute, bo.getRoute());
        lqw.eq(StrUtil.isNotBlank(bo.getStorageClassify()), BaseLocation::getStorageClassify, bo.getStorageClassify());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend1()), BaseLocation::getExtend1, bo.getExtend1());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend2()), BaseLocation::getExtend2, bo.getExtend2());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend3()), BaseLocation::getExtend3, bo.getExtend3());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend4()), BaseLocation::getExtend4, bo.getExtend4());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend5()), BaseLocation::getExtend5, bo.getExtend5());
        lqw.eq(bo.getBranchId() != null, BaseLocation::getBranchId, bo.getBranchId());
        lqw.eq(StrUtil.isNotBlank(bo.getIsDel()), BaseLocation::getIsDel, bo.getIsDel());
        lqw.eq(StrUtil.isNotBlank(bo.getIsDeep()), BaseLocation::getIsDeep, bo.getIsDeep());
        lqw.eq(BaseLocation::getIsDel, IsDelEnum.NORMAL.getValue());
        lqw.orderByDesc(BaseLocation::getCreateTime);
        List<BaseLocationVo> voList = entity2Vo(this.list(lqw));
        return voList;

    }

    /**
     * 实体类转化成视图对象
     *
     * @param collection 实体类集合
     * @return
     */
    private List<BaseLocationVo> entity2Vo(Collection<BaseLocation> collection) {
        List<BaseLocationVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, BaseLocationVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<BaseLocation> page = (Page<BaseLocation>) collection;
            Page<BaseLocationVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page, pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> insertByAddBo(BaseLocationAddBo bo) {
        BaseLocation add = BeanUtil.toBean(bo, BaseLocation.class);
        this.save(add);
        return Result.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> updateByEditBo(BaseLocationEditBo bo) {
        BaseLocation one = getById(bo.getId());
        if (one == null) {
            return Result.err().msg("不存在");
        }
        BaseLocation update = BeanUtil.toBean(bo, BaseLocation.class);
        this.updateById(update);
        return Result.ok();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> deleteWithValidById(List<Long> ids, Boolean isValid) {
        BaseLocation del = new BaseLocation();
        if (isValid == true) {
            del.setIsDel(IsDelEnum.DELETED.getValue());
        } else {
            del.setIsDel(IsDelEnum.NORMAL.getValue());
        }
        LambdaQueryWrapper<BaseLocation> wrapper = new LambdaQueryWrapper<BaseLocation>().in(BaseLocation::getId, ids)
                .eq(BaseLocation::getBranchId, SecurityUtils.getCurrentBranchId());
        this.update(del, wrapper);
        return Result.ok();
    }


    /**
     * 根据id集合查询货位信息
     *
     * @param locationIds
     * @return
     */
    @Override
    public List<BaseLocationVo> queryLocationsByIds(List<Long> locationIds) {
        return this.baseMapper.queryLocationsByIds(locationIds);
    }

    /**
     * 根据id集合查询货位信息
     *
     * @param locationIds
     * @param goodsId
     * @return
     */
    @Override
    public List<BaseLocationVo> queryLocationsPackageByIds(List<Long> locationIds, Long goodsId) {
        return this.baseMapper.queryLocationsPackageByIds(locationIds, goodsId);
    }

    /**
     * 查询货位资料列表
     *
     * @param bo
     * @return
     */
    @Override
    @DataScopeConsignor(branchAlias = "bl")
    public List<BaseLocationVo> queryBaseLocationList(BaseLocationQueryPageBo bo) {
        List<BaseLocationVo> list = this.getBaseMapper().queryBaseLocationList(bo);
        list.forEach(s -> {
            BaseAreaQueryBo areaBo = BeanUtil.toBean(bo, BaseAreaQueryBo.class);
            areaBo.setStorageId(s.getStorageId());
            s.setAreaVoList(iBaseAreaService.queryList(areaBo));
        });
        return list;
    }

    @Override
    @DataScopeConsignor(branchAlias = "bl")
    public List<String> queryBaseLocationTunnelList(BaseLocationQueryListBo bo) {
        BaseLocationQueryPageBo boo = BeanUtil.toBean(bo, BaseLocationQueryPageBo.class);
        List<BaseLocationVo> list = this.getBaseMapper().queryBaseLocationList(boo);
        List<String> listTunnel = list.stream().map(b -> b.getTunnel()).distinct().collect(Collectors.toList());
        return listTunnel;
    }

    /**
     * 根据ids获取区域数据
     *
     * @param ids
     * @return
     */
    public List<BaseLocation> queryBaseLocationByIds(List<Long> ids) {
        LambdaQueryWrapper<BaseLocation> wrapper = new LambdaQueryWrapper<BaseLocation>()
                .in(BaseLocation::getId, ids)
                .eq(BaseLocation::getBranchId, SecurityUtils.getCurrentBranchId())
                .eq(BaseLocation::getIsDel, DeleteFlagEnum.NORMAL.getValue());
        return this.list(wrapper);
    }


    /**
     * 保存或者修改货位资料列表（根据是否有id来判断新增或者修改）
     *
     * @param list
     * @return
     */
    @Override
    public Result<Boolean> saveOrUpdateBaseLocations(ValidList<BaseLocationSaveOrUpdateBo> list) {
        List<BaseLocation> addList = new ArrayList<>();
        List<BaseLocation> updList = new ArrayList<>();
        // 参数校验
        Result<Boolean> resultBo = checkBaseLocationSaveOrUpdateBo(list);
        if (!Result.isOk(resultBo)) {
            return resultBo;
        }
        for (BaseLocationSaveOrUpdateBo bo : list) {
            BaseArea baseArea = iBaseAreaService.getById(bo.getAreaId());
            if (bo.getId() != null) {
                BaseLocation one = getById(bo.getId());
                BaseLocation update = BeanUtil.toBean(bo, BaseLocation.class);
                update.setBranchId(one.getBranchId());
                String code =
                         bo.getTunnel() + "-"
                        + bo.getLocationRow()
                        + bo.getLocationColumn()
                        + bo.getLayer()+"-"
                        +bo.getIsDeep();
                update.setLocationCode(code);
                Result result = checkEntity(update);
                if (!Result.isOk(result)) {
                    return Result.err().msg(result.getMsg());
                }
                updList.add(update);
            } else {
                BaseLocation add = BeanUtil.toBean(bo, BaseLocation.class);
                /**
                 * 显示货位规则为：库区编号+道号+ - + 排+层+列 如：LH01-010101
                 */
                String code = bo.getTunnel() + "-"
                        + bo.getLocationRow()
                        + bo.getLocationColumn()
                        + bo.getLayer()+"-"
                        +bo.getIsDeep();
                add.setLocationCode(code);
                add.setBranchId(SecurityUtils.getCurrentBranchId());
                Result result = checkEntity(add);
                if (!Result.isOk(result)) {
                    return Result.err().msg(result.getMsg());
                }
                addList.add(add);
            }
        }
        this.updateBatchById(updList);
        this.saveBatch(addList);
        return Result.ok();
    }

    private Result<Boolean> checkBaseLocationSaveOrUpdateBo(ValidList<BaseLocationSaveOrUpdateBo> list) {
        // 首先校验请求参数是否出现重复
        boolean b = list.stream().filter(x -> !StringUtils.isNumeric(x.getRoute())).findFirst().isPresent();
        if (b) {
            return Result.err().msg("拣货路径异常");
        }
//        // 显示货位是否重复
//        List<String> listLocationNames = list.stream().map(s -> s.getLocationName()).distinct().collect(Collectors.toList());
//        if (CollectionUtils.isEmpty(listLocationNames)
//                || listLocationNames.size() != list.size()) {
//            return Result.err().msg("货位名称重复!");
//        }
        // 货位id是否重复
        List<String> listLocationCodes = list.stream().map(
                s -> (  s.getTunnel() + "-"
                        + s.getLocationRow()
                        + s.getLocationColumn()
                        + s.getLayer()+"-"
                        + s.getIsDeep()
                )).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(listLocationCodes)
                || listLocationCodes.size() != list.size()) {
            return Result.err().msg("根据规则货位编号重复!");
        }
        // 库区资料
        List<Long> listAreaIds = list.stream().map(s -> s.getAreaId()).distinct().collect(Collectors.toList());
        List<BaseArea> baseAreaList = iBaseAreaService.listByIds(listAreaIds);
        if (CollectionUtils.isEmpty(baseAreaList) || baseAreaList.size() != listAreaIds.size()) {
            return Result.err().msg("库区资料存在异常!");
        }
        // 修改的数据
        List<Long> listLocationIds = list.stream().filter(s -> s.getId() != null).map(s -> s.getId()).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(listLocationIds)) {
            List<BaseLocation> baseLocations = listByIds(listLocationIds);
            if (CollectionUtils.isEmpty(baseLocations) ||
                    listLocationIds.size() != baseLocations.size()) {
                return Result.err().msg("存在货位资料不存在的数据！");
            }
        }
        return Result.ok();
    }

    @Override
    public Result<Boolean> saveBaseLocationMany(BaseLocationManyBo bo) {

        List<BaseLocation> addList = new ArrayList<>();

        if (bo.getStartLocationRow() < 0L || bo.getEndLocationRow() < 0L || bo.getStartLocationRow() > bo.getEndLocationRow()) {
            log.error("起始终止排存在错误:" + bo.toString());
            return Result.err().msg("起始终止排存在错误！");
        }
        if (bo.getStartLocationColumn() < 0L || bo.getEndLocationColumn() < 0L || bo.getStartLocationColumn() > bo.getEndLocationColumn()) {
            log.error("起始终止列存在错误:" + bo.toString());
            return Result.err().msg("起始终止列存在错误！");
        }
        if (bo.getStartLayer() < 0L || bo.getEndLayer() < 0L || bo.getStartLayer() > bo.getEndLayer()) {
            log.error("起始终止层存在错误:" + bo.toString());
            return Result.err().msg("起始终止层存在错误！");
        }
        BaseLocation temp = BeanUtil.toBean(bo, BaseLocation.class);
        // 获取起始终止编码之间的数据
        int rowLength = bo.getEndLocationRow().toString().length();
        int columnLength = bo.getEndLocationRow().toString().length();
        int layerLength = bo.getEndLayer().toString().length();
        // 获取区域编号
        BaseArea baseArea = iBaseAreaService.getById(bo.getAreaId());
        String s = baseArea.getAreaCode() + bo.getTunnel();

        for (Long a = bo.getStartLocationRow(); a <= bo.getEndLocationRow(); a++) {
            for (Long b = bo.getStartLocationColumn(); b <= bo.getEndLocationColumn(); b++) {
                for (Long c = bo.getStartLayer(); c <= bo.getEndLayer(); c++) {
                    BaseLocation baseLocation = new BaseLocation();
                    baseLocation.setAreaId(bo.getAreaId());
                    baseLocation.setTunnel(bo.getTunnel());
                    baseLocation.setLocationRow(a.toString());
                    baseLocation.setLocationColumn(b.toString());
                    baseLocation.setLayer(c.toString());
                    Result result = checkEntity(baseLocation);
                    if (!Result.isOk(result)) {
                        return Result.err().msg(result.getMsg());
                    }
                    // 创建对象
                    String code = s + "-"
                            + String.format("%0" + rowLength + "d", a)
                            + String.format("%0" + columnLength + "d", b)
                            + String.format("%0" + layerLength + "d", c);
                    baseLocation.setLocationCode(code);
                    baseLocation.setLocationName(code);
                    baseLocation.setType(bo.getType());
                    baseLocation.setLogicId(bo.getLogicId());
                    baseLocation.setStorageClassify(bo.getStorageClassify());
                    baseLocation.setLength(bo.getLength());
                    baseLocation.setWidth(bo.getWidth());
                    baseLocation.setHeight(bo.getHeight());
                    baseLocation.setVolume(bo.getLength().multiply(bo.getWidth()).multiply(bo.getHeight()));
                    baseLocation.setSkunum(bo.getSkunum());
                    baseLocation.setIsuse(bo.getIsuse());
                    baseLocation.setBranchId(SecurityUtils.getCurrentBranchId());
                    addList.add(baseLocation);
                }
            }
        }
        this.saveBatch(addList);
        return Result.ok();
    }

    /**
     * 保存或者修改货位（根据是否有id来判断新增或者修改）
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> saveOrUpdateBaseLocation(BaseLocationSaveOrUpdateBo bo) {
        BaseLocation saveOrupDate = null;
        if (bo.getId() != null) {
            BaseLocation one = getById(bo.getId());
            if (one == null) {
                log.error("货位资料不存在:" + bo.toString());
                return Result.err().msg("货位资料不存在！");
            }
        }
        saveOrupDate = BeanUtil.toBean(bo, BaseLocation.class);
        saveOrupDate.setBranchId(SecurityUtils.getCurrentBranchId());
        Result result = checkEntity(saveOrupDate);
        if (!Result.isOk(result)) {
            return Result.err().msg(result.getMsg());
        }
        this.saveOrUpdate(saveOrupDate);
        return Result.ok();
    }

    @Override
    public BaseLocationVo queryLocationById(Long targetLocationId) {
        return baseMapper.queryLocationById(targetLocationId);
    }

    @Override
    public BaseLocationVo queryLocationByCode(String locationCode) {
        return baseMapper.queryLocationByCode(locationCode, SecurityUtils.getCurrentBranchId());
    }

    @Override
    public BaseLocationVo queryLocationByName(String locationName) {
        return baseMapper.queryLocationByName(locationName, SecurityUtils.getCurrentBranchId());
    }


    /**
     * 校验数据 (相同仓下、相同区域、逻辑区域不允许重复)
     *
     * @param entity
     * @return
     */
    private Result<Boolean> checkEntity(BaseLocation entity) {
        Long id = entity.getId() != null ? entity.getId() : -1L;
        // 货位名称不能相同
        LambdaQueryWrapper<BaseLocation> wrapper = new LambdaQueryWrapper<BaseLocation>()
                .eq(BaseLocation::getLocationName, entity.getLocationName())
                .eq(BaseLocation::getIsDel, IsDelEnum.NORMAL.getValue())
                .eq(BaseLocation::getBranchId, entity.getBranchId());
        BaseLocation one = getOne(wrapper);
        if (one != null && !id.equals(one.getId())) {
            log.error("存在货位名称相同的数据：" + entity.toString());
            return Result.err().msg("存在货位名称相同的数据");
        }
        // 货位Code不能相同
        String LocationCode = entity.getAreaId()
                + entity.getTunnel() + "-"
                + entity.getLocationRow()
                + entity.getLayer()
                + entity.getLocationColumn();
        LambdaQueryWrapper<BaseLocation> wrapper2 = new LambdaQueryWrapper<BaseLocation>()
                .eq(BaseLocation::getLocationCode, LocationCode)
                .eq(BaseLocation::getIsDel, IsDelEnum.NORMAL.getValue())
                .eq(BaseLocation::getBranchId, entity.getBranchId());
        BaseLocation one2 = getOne(wrapper);
        if (one != null && !id.equals(one.getId())) {
            log.error("存在货位编号相同的数据：" + entity.toString());
            return Result.err().msg("存在货位编号相同的数据");
        }
        return Result.ok();
    }


    @Override
    public Result<Boolean> switchStatus(Long id, String status) {
        BaseLocation location = new BaseLocation();
        location.setId(id).setIsuse(status);
        return this.updateById(location) ? Result.ok() : Result.err();
    }

    //入库时对双深位巷道中的货位进行处理
    public List<BaseLocationVo> getUseBaseLoction(List<BaseLocationVo> baseLocationVoList){
        BaseLocationVo baseLocationVo = new BaseLocationVo();
        for (int i=0;i<baseLocationVoList.size();i++){
            //当前只有第一巷道为双深位货位
            if (baseLocationVoList.get(i).getTunnel().equals("01")){
                baseLocationVo=baseLocationVoList.get(i);
                //货位为单深位(查看双深位状态是否是已分配状态如果是已分配状态那这个单深位不能放货)
                if (baseLocationVo.getIsDeep().equals("1")){
                    BaseLocation one=null;
                    if (baseLocationVo.getLocationRow().equals("2")){
                        one = this.getOne(new LambdaQueryWrapper<BaseLocation>()
                                .eq(BaseLocation::getLocationRow, "1")
                                .eq(BaseLocation::getLocationColumn, baseLocationVo.getLocationColumn())
                                .eq(BaseLocation::getLayer, baseLocationVo.getLayer()));
                    }
                    if (baseLocationVo.getLocationRow().equals("3")){
                        one = this.getOne(new LambdaQueryWrapper<BaseLocation>()
                                .eq(BaseLocation::getLocationRow, "4")
                                .eq(BaseLocation::getLocationColumn, baseLocationVo.getLocationColumn())
                                .eq(BaseLocation::getLayer, baseLocationVo.getLayer()));

                    }
                    if (one!=null&&one.getLocationStatus().equals("4")){
                        baseLocationVoList.remove(i);
                    }
                }
                //货位为双深位状态(查看单深位状态是否为已分配状态或者有货位状态(已分配状态防止货物还未取走))
                if (baseLocationVo.getIsDeep().equals("2")){
                    BaseLocation one=null;
                    if (baseLocationVo.getLocationRow().equals("1")){
                        one = this.getOne(new LambdaQueryWrapper<BaseLocation>()
                                .eq(BaseLocation::getLocationRow, "2")
                                .eq(BaseLocation::getLocationColumn, baseLocationVo.getLocationColumn())
                                .eq(BaseLocation::getLayer, baseLocationVo.getLayer()));
                    }
                    if (baseLocationVo.getLocationRow().equals("4")){
                        one = this.getOne(new LambdaQueryWrapper<BaseLocation>()
                                .eq(BaseLocation::getLocationRow, "3")
                                .eq(BaseLocation::getLocationColumn, baseLocationVo.getLocationColumn())
                                .eq(BaseLocation::getLayer, baseLocationVo.getLayer()));

                    }
                    if (one!=null&&(one.getLocationStatus().equals("4")||one.getLocationStatus().equals("1"))){
                        baseLocationVoList.remove(i);
                    }
                }
            }
        }
        return baseLocationVoList;
    }

    /**
     * 根据派生分配空货位
     *
     * @param vehicheModel
     * @param batch
     * @return
     */
    @Override
    public Result<BaseLocationVo> assignEmptyLocation( String vehicheModel,String color, String batch,List<BusinDataTaskGoodsVo> businDataTaskGoodsVos) {
        if(businDataTaskGoodsVos !=null && businDataTaskGoodsVos.size()>0){
            BusinDataTaskGoodsVo businDataTaskGoodsVo = businDataTaskGoodsVos.get(0);
            String taskCode = businDataTaskGoodsVo.getTaskCode();
            log.info("分配货位任务号："+taskCode+"  车型："+vehicheModel+"  颜色："+color);
        }
        //获取车型对应的空货位
        BaseLocationQueryListBo bo = new BaseLocationQueryListBo();
        bo.setVehicheModel(vehicheModel);
        bo.setLocationStatus("0");
        bo.setColor(color);
        log.info("保险杠分配货位查询条件："+ JsonUtil.toJSONString(bo));
        List<BaseLocationVo> baseLocationVos = this.baseMapper.queryBaseLocationListByDerive(bo);
        if(baseLocationVos.size()==0){
            //查看缓冲区是否还有货位
            Long bufferArea =Long.valueOf(sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.buffer_area));
            List<BaseLocationVo> baseLocationVoList = baseLocationMapper.getLocationByAreaId(bufferArea);
            log.info("保险杠缓冲区分配到的货位信息："+baseLocationVoList.size());
            if (baseLocationVoList.size()<0) {
                log.info("车型及缓冲区都未查询到空货位");
                return Result.err().msg("当前该派生对应的空货位可用");
            }
            baseLocationVos.addAll(baseLocationVoList);
        }
        //拿到所有可用货位,根据巷道号对双深位的巷道进行处理
//        baseLocationVos=this.getUseBaseLoction(baseLocationVos);
        //空货位所在巷道列表,同时过滤掉已有入库任务的巷道
        List<String> tunnelList = baseLocationVos.stream().map(e -> e.getTunnel()).distinct().collect(Collectors.toList());
        log.info("保险杠分配货位查询到的货位对应的巷道信息："+JsonUtil.toJSONString(tunnelList));
        // TODO 测试注释   要打开
        if(vehicheModel.contains("3UE")){
            for (int i=0;i<tunnelList.size();i++){
                if (tunnelList.get(i).contains("1")||tunnelList.get(i).contains("6")){
                    tunnelList.remove(i);
                }
            }
        }

        //从存在空货位的巷道里选择较优的巷道进行入库
        //首选选择任务数为空或者任务数最少的巷道
        //任务数相同时选取空货位最多的巷道
        List<String> tunnelResult = new ArrayList<>();
        Integer minTaskNum = 0;
        Integer maxEmptyLocationNum = 0;
        for (int i = 0; i < tunnelList.size(); i++) {
            String tunnel = tunnelList.get(i);
            Integer taskNum = tunnelTaskUtil.getTotalTaskNum(tunnel,0);
            int curEmptyNum = baseLocationVos.stream().filter(e -> tunnel.equals(e.getTunnel())).collect(Collectors.toList()).size();
            log.info("保险杠分配之前----当前巷道："+tunnel+" 目前任务数："+taskNum+"  当前空货位数量："+curEmptyNum+"  最小任务数："+minTaskNum+"  最大空货位数："+maxEmptyLocationNum);
            if (minTaskNum == 0 && taskNum.equals(minTaskNum)) {
                if(i != 0){
                    if (curEmptyNum > maxEmptyLocationNum) {
                        tunnelResult.clear();
                        tunnelResult.add(tunnel);
                        maxEmptyLocationNum = curEmptyNum;
                    }
                } else {
                    minTaskNum = taskNum;
                    tunnelResult.add(tunnel);
                    maxEmptyLocationNum = curEmptyNum;
                }
            }else if (minTaskNum == 0) {
                if(i == 0){
                    minTaskNum = taskNum;
                    tunnelResult.add(tunnel);
                    maxEmptyLocationNum = curEmptyNum;
                }
            } else if (minTaskNum != 0 && taskNum.equals(minTaskNum)) {
                if (curEmptyNum > maxEmptyLocationNum) {
                    tunnelResult.clear();
                    tunnelResult.add(tunnel);
                    maxEmptyLocationNum = curEmptyNum;
                }
            } else if (minTaskNum != 0 && taskNum < minTaskNum) {
                minTaskNum = taskNum;
                tunnelResult.clear();
                tunnelResult.add(tunnel);
                maxEmptyLocationNum = curEmptyNum;
            }

            log.info("保险杠分配之后----当前巷道："+tunnel+" 目前任务数："+taskNum+"  当前空货位数量："+curEmptyNum+"  最小任务数："+minTaskNum+"  最大空货位数："+maxEmptyLocationNum);
        }

        log.info("巷道的任务数量："+JsonUtil.toJSONString(tunnelResult));
        //从选取的巷道中选择库位
        if (tunnelResult.size() > 0) {
            String tunnel = tunnelResult.get(0);
            List<BaseLocationVo> resultLocationList = baseLocationVos.stream().filter(e -> tunnel.equals(e.getTunnel())).collect(Collectors.toList());
            BaseLocationVo locationVo = resultLocationList.get(0);
            log.info("分配的货位："+JsonUtil.toJSONString(locationVo));
            //巷道中货位数大于1时，进行分配
            if (resultLocationList.size() > 0) {
                BaseLocationVo assginLocation = assginLocation(resultLocationList,batch,vehicheModel,businDataTaskGoodsVos);
                if (assginLocation != null) {
                    locationVo = assginLocation;
                    log.info("最终分配的货位信息："+assginLocation);
                }
            }

            //确定分配该库位，并将库位状态改为已分配
            this.changeLocationStatus(locationVo.getId(),"4");
            locationVo.setLocationStatus("4");
            return Result.ok().data(locationVo);
        } else {
            // TODO 是否需要逻辑处理，如果在选取的巷道中货位为空时！！
            return Result.err();
        }
    }

    /**
     * 根据产品查找库内库存数量最少的巷道
     *
     * @param goodsNo
     * @param batch
     * @param businDataTaskGoodsVos
     * @return
     */
    @Override
    public Result<BaseLocationVo> assignEmptyLocationByStock(String goodsNo, String vehicheModel, String batch, List<BusinDataTaskGoodsVo> businDataTaskGoodsVos) {
        if (businDataTaskGoodsVos != null && businDataTaskGoodsVos.size() > 0) {
            BusinDataTaskGoodsVo businDataTaskGoodsVo = businDataTaskGoodsVos.get(0);
            String taskCode = businDataTaskGoodsVo.getTaskCode();
            log.info("分配货位任务号：" + taskCode + "  保险杠编号：" + goodsNo);
        }
        //获取车型对应的空货位
        BaseLocationQueryListBo bo = new BaseLocationQueryListBo();
        bo.setGoodsNo(goodsNo);
        bo.setLocationStatus("0");
        log.info("保险杠分配货位查询条件：" + JsonUtil.toJSONString(bo));
        List<BaseLocationVo> baseLocationVos = this.baseMapper.queryBaseLocationListByGoods(bo);
        if (baseLocationVos.size() == 0) {
            //查看缓冲区是否还有货位
            Long bufferArea = Long.valueOf(sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.buffer_area));
            List<BaseLocationVo> baseLocationVoList = baseLocationMapper.getLocationByAreaId(bufferArea);
            log.info("保险杠缓冲区分配到的货位信息：" + baseLocationVoList.size());
            if (baseLocationVoList.size() < 0) {
                log.info("车型及缓冲区都未查询到空货位");
                return Result.err().msg("当前该派生对应的空货位可用");
            }
            baseLocationVos.addAll(baseLocationVoList);
        }
        //拿到所有可用货位,根据巷道号对双深位的巷道进行处理
//        baseLocationVos=this.getUseBaseLoction(baseLocationVos);
        //空货位所在巷道列表,同时过滤掉已有入库任务的巷道
        List<String> tunnelList = baseLocationVos.stream().map(e -> e.getTunnel()).distinct().collect(Collectors.toList());
        log.info("保险杠分配货位查询到的货位对应的巷道信息：" + JsonUtil.toJSONString(tunnelList));
        // TODO 测试注释   要打开
        if (vehicheModel.contains("3UE")) {
            for (int i = 0; i < tunnelList.size(); i++) {
                if (tunnelList.get(i).contains("1") || tunnelList.get(i).contains("6")) {
                    tunnelList.remove(i);
                }
            }
        }

        //从存在空货位的巷道里选择较优的巷道进行入库
        //首选选择任务数为空或者任务数最少的巷道
        //任务数相同时选取空货位最多的巷道;24.06.27改为查询库存数量最少并且空货位数最多的
        List<String> tunnelResult = new ArrayList<>();
        Integer minTaskNum = 0;
        Integer maxEmptyLocationNum = 0;
        Integer minGoodsQty = 0;
        for (int i = 0; i < tunnelList.size(); i++) {
            String tunnel = tunnelList.get(i);
            Integer taskNum = tunnelTaskUtil.getTotalTaskNum(tunnel, 0);
            List<BaseLocationVo> currTunnelLocationVos = baseLocationVos.stream().filter(e -> tunnel.equals(e.getTunnel())).collect(Collectors.toList());
            int curEmptyNum = currTunnelLocationVos.size();
            BaseLocationVo baseLocationVo = currTunnelLocationVos.get(0);
            int currGoodsQty = 0;
            if (baseLocationVo.getGoodQty() !=null){
                currGoodsQty=baseLocationVo.getGoodQty();
            }

            //获取巷道内库存数量最少并且空货位数最多的
            log.info("保险杠分配之前----当前巷道：" + tunnel + " 目前任务数：" + taskNum + "  当前空货位数量：" + curEmptyNum + "  最小任务数：" + minTaskNum + "  最大空货位数：" + maxEmptyLocationNum+" 当前库存量："+currGoodsQty);
            if (minTaskNum == 0 && taskNum.equals(minTaskNum)) {
                if (i != 0) {
                    if (currGoodsQty < minGoodsQty) {
                        minGoodsQty = currGoodsQty;
                        if (curEmptyNum > maxEmptyLocationNum) {
                            tunnelResult.clear();
                            tunnelResult.add(tunnel);
                            maxEmptyLocationNum = curEmptyNum;
                        }
                    }
                } else {
                    minGoodsQty = currGoodsQty;
                    minTaskNum = taskNum;
                    tunnelResult.add(tunnel);
                    maxEmptyLocationNum = curEmptyNum;
                }
            } else if (minTaskNum == 0) {
                if (i == 0) {
                    minGoodsQty = currGoodsQty;
                    minTaskNum = taskNum;
                    tunnelResult.add(tunnel);
                    maxEmptyLocationNum = curEmptyNum;
                }
            } else if (minTaskNum != 0 && taskNum.equals(minTaskNum)) {
                if (currGoodsQty < minGoodsQty) {
                    minGoodsQty = currGoodsQty;
                    if (curEmptyNum > maxEmptyLocationNum) {
                        tunnelResult.clear();
                        tunnelResult.add(tunnel);
                        maxEmptyLocationNum = curEmptyNum;
                    }
                }
            } else if (minTaskNum != 0 && taskNum < minTaskNum) {
                minGoodsQty = currGoodsQty;
                minTaskNum = taskNum;
                tunnelResult.clear();
                tunnelResult.add(tunnel);
                maxEmptyLocationNum = curEmptyNum;
            }

            log.info("保险杠分配之后----当前巷道：" + tunnel + " 目前任务数：" + taskNum + "  当前空货位数量：" + curEmptyNum + "  最小任务数：" + minTaskNum + "  最大空货位数：" + maxEmptyLocationNum+" 当前库存量："+currGoodsQty);
        }

        log.info("巷道的任务数量：" + JsonUtil.toJSONString(tunnelResult));
        //从选取的巷道中选择库位
        if (tunnelResult.size() > 0) {
            String tunnel = tunnelResult.get(0);
            List<BaseLocationVo> resultLocationList = baseLocationVos.stream().filter(e -> tunnel.equals(e.getTunnel())).collect(Collectors.toList());
            BaseLocationVo locationVo = resultLocationList.get(0);
            log.info("分配的货位：" + JsonUtil.toJSONString(locationVo));
            //巷道中货位数大于1时，进行分配
            if (resultLocationList.size() > 0) {
                BaseLocationVo assginLocation = assginLocation(resultLocationList, batch, vehicheModel, businDataTaskGoodsVos);
                if (assginLocation != null) {
                    locationVo = assginLocation;
                    log.info("最终分配的货位信息：" + assginLocation);
                }
            }

            //确定分配该库位，并将库位状态改为已分配
            this.changeLocationStatus(locationVo.getId(), "4");
            locationVo.setLocationStatus("4");
            return Result.ok().data(locationVo);
        } else {
            // TODO 是否需要逻辑处理，如果在选取的巷道中货位为空时！！
            return Result.err();
        }
    }


    //从选取的巷道中选择库位
    private BaseLocationVo assginLocation(List<BaseLocationVo> locationList,String batch,String vehicheModel,List<BusinDataTaskGoodsVo> businDataTaskGoodsVos) {
        BaseLocationVo resultLocationVo = null;
        //根据拣货路径选择最近一个货位
        for (int i = 0; i < locationList.size(); i++) {
            BaseLocationVo locationVo = locationList.get(i);
            log.info("查询到的货位："+JsonUtil.toJSONString(locationVo));
            //如果该货位为双深位，则直接选择该库位
            if ("2".equals(locationVo.getIsDeep())) {
                return locationVo;
            } else {
                // 检查该单深位是否有对应双深位;如果有
                Result<BaseLocationVo> deepLocationResult = this.getDeepLocation(locationVo);
                log.info("单深位是否有双深位：单深位编号："+locationVo.getLocationCode()+"  返回的双深位信息："+deepLocationResult.getData());
                if (HttpStatus.SUCCESS == deepLocationResult.getCode()) {
                    BaseLocationVo deepLocation = deepLocationResult.getData();
                    Result<List<SysStockDetailVo>> sysStockDetailVoResult = iSysStockDetailService.queryByLocation(deepLocation.getId());
                    if (HttpStatus.SUCCESS == sysStockDetailVoResult.getCode()) {
                        List<SysStockDetailVo> sysStockDetailVoList = sysStockDetailVoResult.getData();
                        log.info("双深位的保险杠信息："+JsonUtil.toJSONString(sysStockDetailVoList));
                        int count= 0;

                        List<String> stockGoodsNoList = sysStockDetailVoList.stream().map(SysStockDetailVo::getGoodsNo).distinct().collect(Collectors.toList());
                        log.info("双深位的保险杠条码信息："+JsonUtil.toJSONString(stockGoodsNoList));
                        List<String> taskGoodsNoList = businDataTaskGoodsVos.stream().map(BusinDataTaskGoodsVo::getGoodsNo).distinct().collect(Collectors.toList());
                        log.info("当前任务的保险杠信息："+JsonUtil.toJSONString(taskGoodsNoList));
                        for (String str: taskGoodsNoList) {
                            if(stockGoodsNoList.contains(str)){
                                count++;
                            }
                        }
                        if(!batch.equals(sysStockDetailVoList.get(0).getBatch())
                                || count != stockGoodsNoList.size()
                                || deepLocation.getLocationStatus().equals("2")){
                            log.info("当前批次："+batch+" 双深位批次："+sysStockDetailVoList.get(0).getBatch());
                            log.info("保险杠个数："+count +"双深位保险杠个数："+stockGoodsNoList.size());
                            continue;
                        }else{
                            if(deepLocation.getLocationStatus().equals("4")){
                                log.info("双深位货位已分配："+deepLocation.getLocationCode());
                                continue;
                            }else{
                                return locationVo;
                            }
                        }
                    }else{
                        if(deepLocation.getLocationStatus().equals("0")){
                            log.info("双深位无库存，直接返回："+JsonUtil.toJSONString(deepLocation));
                            return deepLocation;
                        }
                    }
                }else{
                    log.info("单深位货位，返回："+locationVo);
                    return locationVo;
                }
            }
        }
        return resultLocationVo;
    }


    /**
     * 检查当前货位是否有对应双深位
     *
     * @param locationVo 当前货位
     * @return
     */
    @Override
    public Result<BaseLocationVo> getDeepLocation(BaseLocationVo locationVo) {
        if ("1".equals(locationVo.getIsDeep())) {
            BaseLocationQueryListBo bo = new BaseLocationQueryListBo();
            bo.setAreaId(locationVo.getAreaId());
            bo.setTunnel(locationVo.getTunnel());
            bo.setRoute(locationVo.getRoute());
            bo.setIsDeep("2");
            List<BaseLocationVo> baseLocationVos = this.baseMapper.queryBaseLocationListByDerive1(bo);
            if (baseLocationVos.size() > 0) {
                return Result.ok().data(baseLocationVos.get(0));
            }
        }
        return Result.err();
    }

    @Override
    public Result<Boolean> changeLocationStatus(Long id, String status) {
        if (id != null) {
            BaseLocation location = getById(id);
            if (location == null) {
                log.error("货位资料不存在:" + location.toString());
                return Result.err().msg("货位资料不存在！");
            } else {
                //已分配
                if((!"4".equals(status))&&"4".equals(location.getLocationStatus())){
                    tunnelTaskUtil.subInboundTaskNum(location.getTunnel());
                }
                else if("4".equals(status)&&"0".equals(location.getLocationStatus())){
                    tunnelTaskUtil.addInboundTaskNum(location.getTunnel());
                }
                location.setLocationStatus(status);
                return this.updateById(location) ? Result.ok() : Result.err();
            }
        } else {
            return Result.err().msg("货位ID为空！");
        }
    }

    public List<BaseLocationVo> getTUunnel(String goodsId){
        return this.baseMapper.gettunnel(goodsId);
    }


    @Override
    public List<BaseLocationVo> getBaseLocationForMap(BaseLocationQueryPageBo bo) {
        List<BaseLocationVo> list = this.getBaseMapper().getBaseLocationForMap(bo);
        return list;
    }

    public  Result<List<BaseLocationDetailVo>> queryTargetLocation(BaseLocationUrgentBo bo){
        List<BaseLocationDetailVo> list = baseMapper.queryTargetLocation(bo);
        return Result.ok().data(list);
    }
}
