package cn.iocoder.yudao.module.system.service.robot;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.mqtt.api.task.dto.*;
import cn.iocoder.yudao.module.mqtt.enums.task.ExecutionTypeEnum;
import cn.iocoder.yudao.module.system.api.path.vo.RobotClosePathPlantingDTO;
import cn.iocoder.yudao.module.system.config.mqtt.util.MqttUtils;
import cn.iocoder.yudao.module.system.config.poperties.ZnConfigConstant;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningTopicConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotStatusCodeConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTopicConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.RobotTaskDetailActionLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.detail.RobotTaskDetailLogResoVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.detail.RobotTaskDetailLogVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.task.TaskAssignDTO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.cycle.TaskCycleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.housearea.HouseAreaDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselane.WareHouseLaneDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseTakePointDO;
import cn.iocoder.yudao.module.system.dal.dataobject.information.DeviceInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.log.RobotTaskDetailActionLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotChargeLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
import cn.iocoder.yudao.module.system.dal.mysql.cycle.TaskCycleMapper;
import cn.iocoder.yudao.module.system.dal.mysql.housearea.HouseAreaMapper;
import cn.iocoder.yudao.module.system.dal.mysql.houselane.WareHouseLaneMapper;
import cn.iocoder.yudao.module.system.dal.mysql.houselocation.WareHouseLocationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.information.DeviceInformationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotChargeLogMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotInformationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskDetailMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskMapper;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.device.DeviceUseStatusEnum;
import cn.iocoder.yudao.module.system.enums.item.UseStatusEnum;
import cn.iocoder.yudao.module.system.enums.path.PathTaskTypeEnum;
import cn.iocoder.yudao.module.system.enums.redis.RobotCacheLockEnum;
import cn.iocoder.yudao.module.system.enums.robot.*;
import cn.iocoder.yudao.module.system.enums.robot.actionlog.ActionStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.actionlog.CommandIdEnum;
import cn.iocoder.yudao.module.system.enums.robot.charge.ChargeTaskStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotCommandTypeEnum;
//import cn.iocoder.yudao.module.system.service.robot.job.RobotCommonTaskService;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotTaskManualInterventionEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotTaskStageEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.event.EventTypeEnum;
import cn.iocoder.yudao.module.system.mq.message.task.TaskDistributionMessage;
import cn.iocoder.yudao.module.system.mq.producer.task.TaskDistributionProducer;
import cn.iocoder.yudao.module.system.service.houselocation.WareHouseTakePointService;
import cn.iocoder.yudao.module.system.service.information.DeviceInformationService;
import cn.iocoder.yudao.module.system.service.log.RobotTaskDetailActionLogService;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import cn.iocoder.yudao.module.system.service.robot.simulation.RobotSimulationService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import cn.iocoder.yudao.module.system.util.redis.RedissonUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 机器人任务主表 Service 实现类
 *
 * @author 陈宾顺
 */
@Slf4j
@Service
@Validated
public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTaskDO> implements RobotTaskService {

    @Resource
    private RobotTaskMapper taskMapper;

    @Resource
    private WareHouseLocationMapper locationMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private RedissonUtils redissonUtils;

    @Resource
    private RobotTaskDetailMapper taskDetailMapper;

    @Resource
    private RobotTaskDetailService robotTaskDetailService;

    @Resource
    private RobotInformationMapper informationMapper;

    @Resource
    private RobotChargeLogMapper chargeLogMapper;

    @Resource
    private RobotInformationMapper robotInformationMapper;

    @Autowired
    private RobotInformationService robotInformationService;

    @Autowired
    private ZnConfigConstant znConfigConstant;

    @Resource
    private WareHouseLaneMapper houseLaneMapper;

    @Resource
    private HouseAreaMapper houseAreaMapper;

    @Resource
    private TaskCycleMapper taskCycleMapper;

    @Resource
    private DeviceInformationMapper deviceInformationMapper;

    @Autowired
    private MqttUtils mqttUtils;

    @Resource
    private UserOperationLogService userOperationLogService;

    @Resource
    private DeviceInformationService deviceInformationService;

    @Autowired
    private RobotTaskMapper robotTaskMapper;

    @Autowired
    private RobotTaskDetailMapper robotTaskDetailMapper;

    @Resource
    private PositionMapItemService positionMapItemService;

    @Resource
    private RobotTaskDetailActionLogService taskDetailActionLogService;

    @Resource
    private RobotSimulationService robotSimulationService;

    @Resource
    private TaskDistributionProducer taskDistributionProducer;

    @Resource
    private WareHouseTakePointService houseTakePointService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTask(RobotTaskSaveReqVO createReqVO) throws InterruptedException {
        if (znConfigConstant.getTaskNotCheck()) {
            robotSimulationService.createTask(createReqVO);
            return 1L;
        }
        //校验
        doTaskCheck(createReqVO);

        //设置任务号
        if (ObjectUtil.isEmpty(createReqVO.getTaskNo())) {
            String incrementByKey = redisUtil.getIncrementByKey(RobotCacheLockEnum.TASK_NO.getKey());
            createReqVO.setTaskNo(znConfigConstant.getTaskNo() + DateUtils.getYearMonthDay() + incrementByKey);
        }
        //获取库位id
        RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_TASK_ADD_LOCK.getKey());

        if (lock.tryLock(60l, TimeUnit.MINUTES)) {
            try {
                addTask(createReqVO);
            } finally {
                lock.unlock();
            }
        } else {
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }

        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("创建任务 " + createReqVO.getTaskNo())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);

        return 1l;
    }

    /**
     * 校验
     *
     * @param createReqVO
     */
    private void doTaskCheck(RobotTaskSaveReqVO createReqVO) {
        //校验明细
        if (ObjectUtil.isEmpty(createReqVO.getTaskDetailList())) {
            throw exception(TASK_DATA_NOT_FULL);
        }
        //校验循环任务的配置未开启
        if (DoCycleEnum.YES.getType().equals(createReqVO.getDoCycle()) && !znConfigConstant.getDoCycle()) {
            throw exception(TASK_CYCLE_NOT_OPEN);
        }
        //搬空任务只能选择线库或者区域
        if (MoveAllEnum.YES.getType().equals(createReqVO.getDoMoveAll())) {
            for (RobotTaskDetailAddVO robotTaskDetailAddVO : createReqVO.getTaskDetailList()) {
                if (ReleaseTakeEnum.TO_LOCATION.getType().equals(robotTaskDetailAddVO.getTakeType())
                        || ReleaseTakeEnum.TO_LOCATION.getType().equals(robotTaskDetailAddVO.getReleaseType())) {
                    throw exception(TASK_ONLY_CHOOSE_LOCATION);
                }
            }
        }
        //校验机器人是否禁用
        Set<String> robotNos = createReqVO.getTaskDetailList()
                .stream()
                .map(RobotTaskDetailAddVO::getRobotNo)
                .collect(Collectors.toSet());
        if (ObjectUtil.isNotEmpty(robotNos)) {
            List<RobotInformationDO> robots = informationMapper.selectByRobotNos(robotNos);
            String robotNo = robots.stream()
                    .filter(v -> RobotTaskModelEnum.REJECTION.getType().equals(v.getRobotTaskModel()))
                    .map(RobotInformationDO::getRobotNo)
                    .collect(Collectors.joining(" "));

            if (ObjectUtil.isNotEmpty(robotNo)) {
                throw exception0(TASK_CHECK_EXCEPTION.getCode(), "以下机器人已被禁用 " + robotNo, robotNo);
            }
        }
        //校验任务号是否重复
        if (ObjectUtil.isNotEmpty(createReqVO.getTaskNo())) {
            List<RobotTaskDO> taskDOS = taskMapper.selectList(new LambdaQueryWrapperX<RobotTaskDO>()
                    .eq(RobotTaskDO::getTaskNo, createReqVO.getTaskNo()));
            if (ObjectUtil.isNotEmpty(taskDOS)) {
                throw exception(TASK_CHECK_EXIST_NO);
            }
        }

        //移动点位是否为空闲/重复、 处理中的任务
        List<Long> pointList = new ArrayList<>();
        List<String> takeRobotNos = new ArrayList<>();
        List<String> releaseRobotNos = new ArrayList<>();

        for (RobotTaskDetailAddVO robotTaskDetail : createReqVO.getTaskDetailList()) {
            if (RobotTaskTypeEnum.MOVE_TO_POINT.getType().equals(robotTaskDetail.getTaskType())) {
                if (pointList.contains(robotTaskDetail.getReleaseId())) {
                    PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(robotTaskDetail.getReleaseId());
                    throw exception0(TASK_CHECK_EXCEPTION.getCode(), "以下移动的点位重复 " + positionMapItem.getSortNum(), positionMapItem.getSortNum());
                }
                pointList.add(robotTaskDetail.getReleaseId());
            } else if (RobotTaskTypeEnum.TAKE.getType().equals(robotTaskDetail.getTaskType())) {
                if (takeRobotNos.contains(robotTaskDetail.getRobotNo())) {
                    throw exception0(TASK_CHECK_EXCEPTION.getCode(), "一辆车只能有一个仅取货任务 " + robotTaskDetail.getRobotNo(), robotTaskDetail.getRobotNo());
                }
                takeRobotNos.add(robotTaskDetail.getRobotNo());
            } else if (RobotTaskTypeEnum.RELEASE.getType().equals(robotTaskDetail.getTaskType())) {
                if (releaseRobotNos.contains(robotTaskDetail.getRobotNo())) {
                    throw exception0(TASK_CHECK_EXCEPTION.getCode(), "一辆车只能有一个仅放货任务 " + robotTaskDetail.getRobotNo(), robotTaskDetail.getRobotNo());
                }
                releaseRobotNos.add(robotTaskDetail.getRobotNo());
            }
        }

        if (ObjectUtil.isNotEmpty(pointList)) {
            List<PositionMapItemDO> positionMapItemList = positionMapItemService.getPositionMapItemByIds(pointList);
            List<Long> list = positionMapItemList.stream()
                    .filter(v -> !UseStatusEnum.FREE.getType().equals(v.getUseStatus()))
                    .map(PositionMapItemDO::getSortNum)
                    .collect(Collectors.toList());
            if (ObjectUtil.isNotEmpty(list)) {
                String join = StringUtils.join(list, ",");
                throw exception0(TASK_CHECK_EXCEPTION.getCode(), "以下移动的点位非空闲 " + join, join);
            }

            List<Long> doingTaskItemIds = robotTaskDetailService.getDoIngTaskItemIdsByItemIds(pointList);
            if (ObjectUtil.isEmpty(doingTaskItemIds)) {
                return;
            }
            String sortNumStr = getSortNumStr(doingTaskItemIds);
            throw exception0(TASK_CHECK_EXCEPTION.getCode(), "以下移动的点位存在处理中的任务 " + sortNumStr, sortNumStr);
        }

        if (ObjectUtil.isNotEmpty(takeRobotNos)) {
            RobotTaskDetailDO takeTask = taskDetailMapper.selectOne(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                    .in(RobotTaskDetailDO::getRobotNo, takeRobotNos)
                    .in(RobotTaskDetailDO::getTaskStatus, RobotTaskStatusEnum.NEW.getType(), RobotTaskStatusEnum.DOING.getType())
                    .eq(RobotTaskDetailDO::getTaskType, RobotTaskTypeEnum.TAKE.getType())
                    .last("limit 1"));
            if (ObjectUtil.isNotEmpty(takeTask)) {
                throw exception0(TASK_CHECK_EXCEPTION.getCode(), "一辆车只能有一个仅取货任务 " + takeTask.getRobotNo(), takeTask.getRobotNo());
            }
        }

        if (ObjectUtil.isNotEmpty(releaseRobotNos)) {
            RobotTaskDetailDO releaseTask = taskDetailMapper.selectOne(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                    .in(RobotTaskDetailDO::getRobotNo, releaseRobotNos)
                    .in(RobotTaskDetailDO::getTaskStatus, RobotTaskStatusEnum.NEW.getType(), RobotTaskStatusEnum.DOING.getType())
                    .eq(RobotTaskDetailDO::getTaskType, RobotTaskTypeEnum.RELEASE.getType())
                    .last("limit 1"));
            if (ObjectUtil.isNotEmpty(releaseTask)) {
                throw exception0(TASK_CHECK_EXCEPTION.getCode(), "一辆车只能有一个仅放货任务 " + releaseTask.getRobotNo(), releaseTask.getRobotNo());
            }
        }
    }

    public String getSortNumStr(List<Long> pointList) {
        List<PositionMapItemDO> positionMapItemList = positionMapItemService.getPositionMapItemByIds(pointList);
        List<Long> list = positionMapItemList.stream().map(PositionMapItemDO::getSortNum)
                .collect(Collectors.toList());
        return StringUtils.join(list, ",");
    }

    /**
     * 添加任务
     *
     * @param createReqVO
     */
    @Transactional(rollbackFor = Exception.class)
    public void addTask(RobotTaskSaveReqVO createReqVO) {
        RobotTaskDO task = BeanUtils.toBean(createReqVO, RobotTaskDO.class);
        task.setRemainingCycleNumber(task.getCycleNumber());
        task.setStartTime(null);
        task.setEndTime(null);
        taskMapper.insert(task);

        List<Long> laneIds = new ArrayList<>();
        List<Long> areaIds = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(task.getSkuInfo()) && znConfigConstant.getTask().getCheckSkuInfo()) {
            List<WareHouseLaneDO> wareHouseLaneDOS = houseLaneMapper.selectList(new LambdaQueryWrapper<WareHouseLaneDO>()
                    .eq(WareHouseLaneDO::getLaneMsg, task.getSkuInfo()));
            if (ObjectUtil.isNotEmpty(wareHouseLaneDOS)) {
                laneIds = wareHouseLaneDOS.stream().map(WareHouseLaneDO::getId).collect(Collectors.toList());
            }
            List<HouseAreaDO> houseAreaDOS = houseAreaMapper.selectList(new LambdaQueryWrapper<HouseAreaDO>()
                    .eq(HouseAreaDO::getSkuInfo, task.getSkuInfo()));
            if (ObjectUtil.isNotEmpty(houseAreaDOS)) {
                areaIds = houseAreaDOS.stream().map(HouseAreaDO::getId).collect(Collectors.toList());
            }
        }

        //查找库位
        List<Long> locationIds = new ArrayList<>();
        if (MoveAllEnum.NO.getType().equals(createReqVO.getDoMoveAll())) {
            locationIds = setSingleLocationIdNo(createReqVO.getTaskDetailList(), task, laneIds, areaIds);
        } else {
            locationIds = setAllLocationIdNo(createReqVO, task.getId(), laneIds, areaIds, task.getSkuInfo());
        }

        // 插入
        createReqVO.getTaskDetailList()
                .forEach(taskDetail -> {
                    taskDetail.setRobotTaskId(task.getId());
                });
        robotTaskDetailService.insertRobotDetailList(createReqVO.getTaskDetailList());

        List<List<Long>> fromPartition = Lists.partition(locationIds, 100);
        fromPartition.forEach(list -> {
            locationMapper.updateLocationLockList(list, task.getId(), LocationLockEnum.NO.getType());
        });

        /*if (znConfigConstant.getDoCycle() && ObjectUtil.isNotEmpty(createReqVO.getDoCycle())
                && ZeroOneEnum.ONE.getType().equals(createReqVO.getDoCycle().intValue())) {
            addCycle(task.getId(), createReqVO.getTaskDetailList());
        }*/
    }

    @Transactional(rollbackFor = Exception.class)
    public void addCycle(Long id, List<RobotTaskDetailAddVO> taskDetailList) {
        List<TaskCycleDO> cycleDOList = new ArrayList<>();

        List<Long> laneIds = new ArrayList<>();
        List<Long> areaIds = new ArrayList<>();
        List<Long> locationIds = new ArrayList<>();

        for (RobotTaskDetailAddVO detailAddVO : taskDetailList) {

            if (ReleaseTakeEnum.TO_LANE.getType().equals(detailAddVO.getTakeType())) {
                laneIds.add(detailAddVO.getTakeId());
            } else if (ReleaseTakeEnum.TO_AREA.getType().equals(detailAddVO.getTakeType())) {
                areaIds.add(detailAddVO.getTakeId());
            } else if (ReleaseTakeEnum.TO_LOCATION.getType().equals(detailAddVO.getTakeType())) {
                locationIds.add(detailAddVO.getTakeId());
            }

            if (ReleaseTakeEnum.TO_LANE.getType().equals(detailAddVO.getReleaseType())) {
                laneIds.add(detailAddVO.getReleaseId());
            } else if (ReleaseTakeEnum.TO_AREA.getType().equals(detailAddVO.getReleaseType())) {
                areaIds.add(detailAddVO.getReleaseId());
            } else if (ReleaseTakeEnum.TO_LOCATION.getType().equals(detailAddVO.getReleaseType())) {
                locationIds.add(detailAddVO.getReleaseId());
            }
        }

        LambdaQueryWrapper<WareHouseLocationDO> wrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotEmpty(laneIds)) {
            wrapper.or(w -> w.in(WareHouseLocationDO::getLaneId, laneIds));
        }
        if (ObjectUtil.isNotEmpty(areaIds)) {
            wrapper.or(w -> w.in(WareHouseLocationDO::getAreaId, areaIds));
        }
        if (ObjectUtil.isNotEmpty(locationIds)) {
            wrapper.or(w -> w.in(WareHouseLocationDO::getId, locationIds));
        }

        List<WareHouseLocationDO> wareHouseLocationDOS = locationMapper.selectList(wrapper);

        wareHouseLocationDOS
                .stream()
                .map(WareHouseLocationDO::getMapItemId)
                .forEach(mapItemId -> {
                    TaskCycleDO build = TaskCycleDO.builder().robotTaskId(id).mapItemId(mapItemId).build();
                    cycleDOList.add(build);
                });
        taskCycleMapper.insertBatch(cycleDOList);

    }

    /**
     * 关闭任务
     *
     * @param updateReqVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeTask(RobotTaskSaveReqVO updateReqVO) {
        // 校验存在
        validateTaskExists(updateReqVO.getId());
        if (ObjectUtil.isEmpty(updateReqVO.getId())) {
            throw exception(TASK_CHECK_ID_EXCEPTION);
        }
        // 更新
        //修改优先级需要订单状态为未开始/处理中
        RobotTaskDO robotTaskDO = taskMapper.selectById(updateReqVO.getId());
        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.queryByTaskId(updateReqVO.getId());

        List<Long> locationIds = new ArrayList<>();
        List<Long> detailIds = new ArrayList<>();
        Set<String> robotNos = new HashSet<>();

        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("关闭任务 " + robotTaskDO.getTaskNo())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);

        for (RobotTaskDetailDO taskDetailDO : taskDetailDOS) {
            if (!RobotTaskDetailStatusEnum.NEW.getType().equals(taskDetailDO.getTaskStatus())
                    && !RobotTaskDetailStatusEnum.DOING.getType().equals(taskDetailDO.getTaskStatus())) {
                continue;
            }
            //后期需做状态映射
            taskDetailDO.setTaskStatus(updateReqVO.getTaskStatus());
            taskDetailDO.setTaskStage(RobotTaskStageEnum.CLOSE.getType());
            taskDetailDO.setManualIntervention(RobotTaskManualInterventionEnum.RCS_CLOSE.getType());
            taskDetailDO.setManualInterventionTime(LocalDateTime.now());

            /*if (RobotTaskTypeEnum.CHARGE.getType().equals(taskDetailDO.getTaskType())
                    && RobotTaskTypeEnum.PARK.getType().equals(taskDetailDO.getTaskType())) {
                continue;
            }*/

            if (ObjectUtil.isNotEmpty(taskDetailDO.getRobotNo())) {
                robotNos.add(taskDetailDO.getRobotNo());
                detailIds.add(taskDetailDO.getId());
            }

            if (ReleaseTakeEnum.isLocation(taskDetailDO.getTakeType()) && ObjectUtil.isNotEmpty(taskDetailDO.getFromLocationId())) {
                locationIds.add(taskDetailDO.getFromLocationId());
            }
            if (ReleaseTakeEnum.isLocation(taskDetailDO.getReleaseType()) && ObjectUtil.isNotEmpty(taskDetailDO.getToLocationId())) {
                locationIds.add(taskDetailDO.getToLocationId());
            }

            String mac = robotInformationService.getMacByRobotNo(taskDetailDO.getRobotNo());

            closeTaskDetail(taskDetailDO.getId().toString(), mac, PathTaskTypeEnum.getTaskType(taskDetailDO.getTaskType()));

            RobotClosePathPlantingDTO closePathPlanting = RobotClosePathPlantingDTO.builder()
                    .robotNo(taskDetailDO.getRobotNo())
                    .id(taskDetailDO.getId().toString())
                    .build();
//            commonApi.commonMethod(closePathPlanting, PathPlanningTopicConstant.KILL_TASK);
            mqttUtils.pub(PathPlanningTopicConstant.KILL_TASK, JSON.toJSONString(closePathPlanting));
        }

        RobotTaskDO updateObj = BeanUtils.toBean(updateReqVO, RobotTaskDO.class);
        taskMapper.updateById(updateObj);

        taskDetailMapper.updateById(taskDetailDOS);

//        taskCycleMapper.deletByRobotTaskId(robotTaskDO.getId());

        if (ObjectUtil.isNotEmpty(locationIds)) {
            locationMapper.releaseLocationLockList(locationIds, robotTaskDO.getId()
                    , LocationLockEnum.YES.getType());
        }

        if (ObjectUtil.isEmpty(robotNos)) {
            return;
        }

        List<RobotInformationDO> robotInformationDOS = informationMapper.selectList(new LambdaQueryWrapper<RobotInformationDO>()
                .eq(RobotInformationDO::getRobotStatus, RobotStatusEnum.DOING.getType())
                .in(RobotInformationDO::getTaskDetailId, detailIds)
                .in(RobotInformationDO::getRobotNo, robotNos));
        if (ObjectUtil.isEmpty(robotInformationDOS)) {
            return;
        }

        for (RobotInformationDO robotInformationDO : robotInformationDOS) {
            String cargoDetectedKey = RobotTaskChcheConstant.ROBOT_CARGO_DETECTED + robotInformationDO.getMacAddress();
            Object cargoDetected = redisUtil.get(cargoDetectedKey);
            if (ObjectUtil.isNotEmpty(cargoDetected) && RobotStatusCodeConstant.CARGO_DETECTED.equals(Boolean.parseBoolean(String.valueOf(cargoDetected)))) {
                robotInformationDO.setRobotTaskModel(RobotTaskModelEnum.REJECTION.getType());
            }

            robotInformationDO.setRobotStatus(RobotStatusEnum.STAND_BY.getType());
        }

        informationMapper.updateById(robotInformationDOS);
    }

    @Override
    public void closeTaskDetail(String id, String mac, String orderType) {
        RobotAcceptTaskDTO robotTask = new RobotAcceptTaskDTO();
        robotTask.setOrderId(id);
        robotTask.setOrderType(orderType);
        robotTask.setTopic(RobotTopicConstant.ROBOT_TASK_MOVE_TOPIC + mac);
        robotTask.setExecutionType(ExecutionTypeEnum.CANCEL.getType());
//        commonApi.commonMethod(robotTask, robotTask.getTopic());
        mqttUtils.pub(robotTask.getTopic(), JSON.toJSONString(robotTask));
    }

    /**
     * 校验是否存在未完成的任务
     */
    @Override
    public void checkHaveDoingTask() {

        //暂时注释
        if (true) {
            return;
        }

        List<RobotTaskDO> taskDOS = taskMapper.selectList(new LambdaQueryWrapper<RobotTaskDO>()
                .in(RobotTaskDO::getTaskStatus, RobotTaskStatusEnum.NEW.getType(), RobotTaskStatusEnum.DOING.getType()));
        if (ObjectUtil.isNotEmpty(taskDOS)) {
            log.info("编辑地图存在未完成的任务");
            throw exception(TASK_CHECK_HAVE_DOING_TASK);
        }

        /*List<String> commandTypes = PathTaskTypeEnum.getMistakeTaskTypes();
        List<RobotTaskDetailActionLogDO> actionLogDOList = taskDetailActionLogMapper.getMistakeTaskByCommandType(commandTypes);
        if (ObjectUtil.isNotEmpty(actionLogDOList)) {
            log.info("编辑地图存在未完成的移动到等待点/自动充电任务");
            throw exception(TASK_CHECK_HAVE_DOING_TASK);
        }*/
    }

    /**
     * PP分配任务
     *
     * @param message
     */
    @Override
    public void assignTasks(String message) {
        log.info("111111PP路径规划分配任务,开始更新任务状态 :{}", message);
        TaskAssignDTO taskAssignDTO = JSON.parseObject(message, TaskAssignDTO.class);

        String mac = robotInformationService.getMacByRobotNo(taskAssignDTO.getRobotNo());
        String robotDoingActionKey = RobotTaskChcheConstant.ROBOT_QUERY_DOING_ACTION + mac;
        redisUtil.del(robotDoingActionKey);
        redisUtil.del(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + mac);

        Map<Long, String> deviceNoMap = new HashMap<>();
        Integer robotStatus = RobotStatusEnum.DOING.getType();
        //释放ware_position_map_item的使用状态，并且将ActionLog设置为完成
        releaseMapItemUseStatus(taskAssignDTO.getRobotNo());

        RobotChargeLogDO robotChargeLogs = null;

        if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(taskAssignDTO.getOrderType())
                || PathTaskTypeEnum.CHARGE.getType().equals(taskAssignDTO.getOrderType())) {
            robotChargeLogs = chargeLogMapper.selectOne(new LambdaQueryWrapperX<RobotChargeLogDO>()
                    .eq(RobotChargeLogDO::getTaskDetailId, taskAssignDTO.getOrderId())
                    .orderByDesc(RobotChargeLogDO::getCreateTime)
                    .last("limit 1"));

            chargeLogMapper.updateChargStatusByTaskId(taskAssignDTO.getOrderId(), ChargeTaskStatusEnum.CHARGEING.getType());
            robotStatus = RobotStatusEnum.CHARGE.getType();
            if (ObjectUtil.isNotEmpty(robotChargeLogs) && ObjectUtil.isNotEmpty(robotChargeLogs.getTaskDetailId())) {
                deviceNoMap.put(robotChargeLogs.getTaskDetailId(), robotChargeLogs.getDeviceNo());
            }

            if (ObjectUtil.isNotEmpty(robotChargeLogs) && ObjectUtil.isNotEmpty(robotChargeLogs.getDeviceNo())) {
                setDeviceUseing(robotChargeLogs.getDeviceNo(), taskAssignDTO.getRobotNo());
            }
        }

//        chargeDone(taskAssignDTO.getRobotNo());

        robotInformationMapper.updateRobotListStatus(taskAssignDTO.getRobotNo(), robotStatus, taskAssignDTO.getOrderId());

        RobotTaskDO robotTaskDO = null;
        if (PathTaskTypeEnum.MOVE_TO_PP_POINT.getType().equals(taskAssignDTO.getOrderType())) {
            robotTaskDO = ppCreateMove(taskAssignDTO);
        } else {
            robotTaskDO = setTaskDoing(taskAssignDTO.getOrderId(), taskAssignDTO.getRobotNo(), deviceNoMap, taskAssignDTO.getWaitId());
        }

        RobotTaskDetailActionLogSaveReqVO logOne = new RobotTaskDetailActionLogSaveReqVO();
        logOne.setCommandType(taskAssignDTO.getOrderType());
        String actionMsg = taskAssignDTO.getRobotActionMsg() + robotTaskDO.getTaskNo();
        logOne.setActionMsg(actionMsg);
        logOne.setRobotNo(taskAssignDTO.getRobotNo());
        logOne.setOriginalRobotNo(taskAssignDTO.getRobotNo());
        logOne.setStartTime(LocalDateTime.now());
        logOne.setTaskNo(robotTaskDO.getTaskNo());
        logOne.setCommandId(-1L);
        logOne.setTaskDetailId(taskAssignDTO.getOrderId());
        Long mapId = robotInformationService.getRobotMapIdByRobotNo(taskAssignDTO.getRobotNo());
        if (ObjectUtil.isNotEmpty(mapId)) {
            logOne.setPositionMapId(mapId);
        }
        taskDetailActionLogService.createTaskDetailActionLog(logOne);

        try {
            TaskDistributionMessage mess = new TaskDistributionMessage(this, taskAssignDTO.getOrderId() + "",
                    EventTypeEnum.TASK_DISTRIBUTION.getType());
            taskDistributionProducer.sendSmsSendMessage(mess);
        } catch (Exception e) {
            log.info(e.getMessage());
        }
    }


    private RobotTaskDO ppCreateMove(TaskAssignDTO taskAssignDTO) {
        RobotTaskDO task = new RobotTaskDO();
        String incrementByKey = redisUtil.getIncrementByKey(RobotCacheLockEnum.TASK_NO.getKey());
        task.setTaskNo(znConfigConstant.getMoveNo() + DateUtils.getYearMonthDay() + incrementByKey);
        task.setId(IdUtil.getSnowflakeNextId());
        task.setCycleNumber(0L);
        task.setRemainingCycleNumber(0L);
        task.setStartTime(LocalDateTime.now());
        task.setTaskStatus(RobotTaskStatusEnum.DOING.getType());

        PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(Long.valueOf(taskAssignDTO.getWaitId()));
        RobotTaskDetailDO taskDetailDO = new RobotTaskDetailDO();
        taskDetailDO.setId(taskAssignDTO.getOrderId());
        taskDetailDO.setRobotTaskId(task.getId());
        taskDetailDO.setTaskType(RobotTaskTypeEnum.MOVE_TO_POINT.getType());
        taskDetailDO.setReleaseType(ReleaseTakeEnum.TO_LOCATION.getType());
        taskDetailDO.setReleaseId(Long.valueOf(taskAssignDTO.getWaitId()));
        taskDetailDO.setToLocationId(Long.valueOf(taskAssignDTO.getWaitId()));
        taskDetailDO.setToLocationNo(positionMapItem.getSortNum() + "");
        taskDetailDO.setRobotNo(taskAssignDTO.getRobotNo());
        taskDetailDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
        taskDetailDO.setStartTime(LocalDateTime.now());

        robotTaskMapper.insert(task);
        robotTaskDetailMapper.insert(taskDetailDO);

        return task;
    }

    /**
     * 释放ware_position_map_item的使用状态
     *
     * @param robotNo
     */
    private void releaseMapItemUseStatus(String robotNo) {
        RobotTaskDetailActionLogDO actionLog = taskDetailActionLogService.getLastTaskByRobotNo(robotNo, CommandIdEnum.TASK.getType());
        if (ObjectUtil.isNotEmpty(actionLog) && ActionStatusEnum.DOING.getType().equals(actionLog.getActionStatus())) {
            actionLog.setActionStatus(ActionStatusEnum.DONE.getType());
            actionLog.setEndTime(LocalDateTime.now());
            taskDetailActionLogService.updateTaskDetailActionLogs(Collections.singletonList(actionLog));
        }
        //前一个任务是移动到点位或者移动到等待点，需要把点位状态改为空闲
        if (ObjectUtil.isEmpty(actionLog) || (!PathTaskTypeEnum.MOVE_TO_POINT.getType().equals(actionLog.getCommandType()))
                && !PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(actionLog.getCommandType())) {
            return;
        }

        RobotTaskDetailDO robotTaskDetail = taskDetailMapper.selectById(actionLog.getTaskDetailId());
        if (ObjectUtil.isEmpty(robotTaskDetail)) {
            return;
        }
        PositionMapItemSaveReqVO positionMapItemSaveReq = new PositionMapItemSaveReqVO();
        positionMapItemSaveReq.setId(robotTaskDetail.getReleaseId());
        positionMapItemSaveReq.setUseStatus(UseStatusEnum.FREE.getType());
        positionMapItemService.updatePositionMapItem(positionMapItemSaveReq);
    }

    /**
     * 更新设备使用中
     *
     * @param deviceNo
     * @param robotNo
     */
    private void setDeviceUseing(String deviceNo, String robotNo) {
        deviceInformationMapper.updateDeviceUseStatus(deviceNo, DeviceUseStatusEnum.USEING.getType(), robotNo);
    }

    /**
     * 发送任务给车机
     *
     * @param v
     */
    private void sendTaskToRobot(RobotTaskDetailDO v, TaskAssignDTO taskAssignDTO) {
        String mac = robotInformationService.getMacByRobotNo(taskAssignDTO.getRobotNo());
        RobotAssignTaskDataDTO robotAssignTask = getEmptyRobotAssignTaskData();
        RobotAssignTaskDTO build = RobotAssignTaskDTO.builder()
                .topic(RobotTopicConstant.ROBOT_TASK_TOPIC + mac)
                .orderType(taskAssignDTO.getOrderType())
                .executionType(ExecutionTypeEnum.DEFAULT.getType())
                .orderId(taskAssignDTO.getOrderId().toString())
                .data(Lists.newArrayList(robotAssignTask))
                .build();
        if (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(taskAssignDTO.getOrderType())
                || PathTaskTypeEnum.TAKE.getType().equals(taskAssignDTO.getOrderType())
                || PathTaskTypeEnum.RELEASE.getType().equals(taskAssignDTO.getOrderType())) {
            RobotAssignTaskDataDTO robotAssignTaskData = getRobotAssignTaskData(v, taskAssignDTO);
            List<RobotAssignTaskDataDTO> data = build.getData();
            data.add(robotAssignTaskData);
        } else if (PathTaskTypeEnum.CHARGE.getType().equals(taskAssignDTO.getOrderType())
                || PathTaskTypeEnum.AUTO_CHARGE.getType().equals(taskAssignDTO.getOrderType())) {
            RobotAssignTaskDataDTO robotAssignTaskData = new RobotAssignTaskDataDTO();
            robotAssignTaskData.setCommandType(RobotCommandTypeEnum.WORK_START_CHARGE.getType());
            List<RobotAssignTaskDataDTO> data = build.getData();
            data.add(robotAssignTaskData);
        }
        log.info("发送任务给车机 :{}", JSON.toJSONString(build));
//        commonApi.commonMethod(build, build.getTopic());
        mqttUtils.pub(build.getTopic(), JSON.toJSONString(build));
    }

    public RobotAssignTaskDataDTO getEmptyRobotAssignTaskData() {
        RobotAssignTaskDataDTO take = new RobotAssignTaskDataDTO();
        take.setCommandType(RobotCommandTypeEnum.MOVE_POSES.getType());
        List<Pose2ds> pose2ds = new ArrayList<>();
        RobotAssignTaskArgDTO build = RobotAssignTaskArgDTO.builder().pose2ds(pose2ds).build();
        take.setArg(Arrays.asList(build));
        return take;
    }

    public RobotAssignTaskDataDTO getRobotAssignTaskData(RobotTaskDetailDO v, TaskAssignDTO taskAssignDTO) {

        RobotAssignTaskDataDTO take = new RobotAssignTaskDataDTO();
        RobotAssignTaskArgDTO build = null;
        WareHouseLocationDO location = null;
        if (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(taskAssignDTO.getOrderType()) ||
                PathTaskTypeEnum.TAKE.getType().equals(taskAssignDTO.getOrderType())) {
            take.setCommandType(RobotCommandTypeEnum.WORK_PICK_UP_GOODS.getType());
            location = locationMapper.selectById(v.getFromLocationId());
            build = RobotAssignTaskArgDTO.builder()
                    .level(Double.valueOf(location.getLocationStorey()))
                    .offsetHeight(znConfigConstant.getRobotConfig().getOffsetHeight())
                    .build();
            take.setArg(Arrays.asList(build));
        } else if (PathTaskTypeEnum.RELEASE.getType().equals(taskAssignDTO.getOrderType())) {
            take.setCommandType(RobotCommandTypeEnum.WORK_DROP_OFF_GOODS.getType());
            location = locationMapper.selectById(v.getToLocationId());
            build = RobotAssignTaskArgDTO.builder()
                    .level(Double.valueOf(location.getLocationStorey()))
                    .offsetHeight(znConfigConstant.getRobotConfig().getOffsetHeight())
                    .build();
        }

        if (ObjectUtil.isEmpty(location.getLocationTrayHeight())) {
            setRobotAssignTaskArgHeigth(location, build);
        } else {
            build.setHeight(Double.valueOf(location.getLocationTrayHeight() + ""));
        }

        take.setArg(Arrays.asList(build));

        return take;
    }

    private void setRobotAssignTaskArgHeigth(WareHouseLocationDO location, RobotAssignTaskArgDTO build) {
        Integer locationStorey = location.getLocationStorey() - 1;
        double height = locationStorey * znConfigConstant.getRobotConfig().getDefaultTrayHeight();
        build.setHeight(height);
    }

    public RobotTaskDO setTaskDoing(Long detailId, String robotNo, Map<Long, String> deviceNoMap,
                                    String waitId) {
        RobotTaskDetailDO taskDetailDO = taskDetailMapper.selectById(detailId);
        taskDetailDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
        taskDetailDO.setStartTime(LocalDateTime.now());
        if (ObjectUtil.isEmpty(taskDetailDO.getRobotNo())) {
            taskDetailDO.setRobotNo(robotNo);
        }
        if (ObjectUtil.isNotEmpty(deviceNoMap) && ObjectUtil.isNotEmpty(deviceNoMap.get(taskDetailDO.getId()))) {
            taskDetailDO.setToLocationNo(deviceNoMap.get(taskDetailDO.getId()));
        }

        if (RobotTaskTypeEnum.PARK.getType().equals(taskDetailDO.getTaskType())
                && ObjectUtil.isNotEmpty(waitId)) {
            PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(Long.valueOf(waitId));
            if (ObjectUtil.isNotEmpty(positionMapItem)) {
                taskDetailDO.setToLocationNo(positionMapItem.getSortNum() + "");
            }
            taskDetailDO.setToLocationId(Long.valueOf(waitId));
        }

        taskDetailMapper.updateById(taskDetailDO);
        RobotTaskDO robotTaskDO = taskMapper.selectById(taskDetailDO.getRobotTaskId());
        RobotTaskDO task = new RobotTaskDO();
        task.setId(taskDetailDO.getRobotTaskId());
        if (ObjectUtil.isEmpty(robotTaskDO.getStartTime())) {
            task.setStartTime(LocalDateTime.now());
        }
        task.setTaskStatus(RobotTaskStatusEnum.DOING.getType());
        taskMapper.updateById(task);
        task.setTaskNo(robotTaskDO.getTaskNo());
        return task;
    }

    /**
     * 设置放货和取货的id
     *
     * @param createReqVO
     * @param taskId
     */
    @Transactional(rollbackFor = Exception.class)
    public List<Long> setAllLocationIdNo(RobotTaskSaveReqVO createReqVO, Long taskId,
                                         List<Long> laneIds, List<Long> areaIds, String skuInfo) {
        List<RobotTaskDetailAddVO> taskDetailList = createReqVO.getTaskDetailList();

        List<RobotTaskDetailAddVO> newTaskDetailList = new ArrayList<>();
        List<Long> mapItemIds = new ArrayList<>();
        if (znConfigConstant.getDoCycle()) {
            List<TaskCycleDO> taskCycleDOS = taskCycleMapper.selectList(new LambdaQueryWrapper<TaskCycleDO>());
            if (ObjectUtil.isNotEmpty(taskCycleDOS)) {
                mapItemIds = taskCycleDOS.stream().map(TaskCycleDO::getMapItemId).collect(Collectors.toList());
            }
        }
        List<WareHouseLocationDO> wareHouseLocationDOS = locationMapper.selectList(new LambdaQueryWrapper<WareHouseLocationDO>()
                .eq(WareHouseLocationDO::getLocationEnable, LocationEnableEnum.NO.getType()));
        if (ObjectUtil.isNotEmpty(wareHouseLocationDOS)) {
            List<Long> mapItemList = wareHouseLocationDOS.stream().map(WareHouseLocationDO::getMapItemId)
                    .collect(Collectors.toList());
            mapItemIds.addAll(mapItemList);
        }
        //被此次任务锁定的空库位id
        List<Long> toLocationIds = new ArrayList<>();
        //被此次任务锁定的有货库位id
        List<Long> fromLocationIds = new ArrayList<>();
        for (RobotTaskDetailAddVO robotTaskVo : taskDetailList) {
            Set<Long> mapIds = new HashSet<>();
            if (ObjectUtil.isNotEmpty(robotTaskVo.getRobotNo())) {
                RobotInformationPageReqVO pageReqVO = new RobotInformationPageReqVO();
                pageReqVO.setRobotNo(robotTaskVo.getRobotNo());
                mapIds = informationMapper.selectPage(pageReqVO).getList()
                        .stream()
                        .findFirst()
                        .map(RobotInformationDO::getFloorAreaJson)
                        .orElse(new HashSet<>());
            }
            //查找有货且非锁定的库位
            WareHouseLocationDO query = null;
            if (ReleaseTakeEnum.TO_LANE.getType().equals(robotTaskVo.getTakeType())) {
                query = WareHouseLocationDO.builder()
                        .laneId(robotTaskVo.getTakeId())
                        .locationEnable(LocationEnableEnum.YES.getType())
                        .locationLock(LocationLockEnum.YES.getType())
                        .locationUseStatus(LocationUseStatusEnum.YES.getType())
                        .build();
            } else if (ReleaseTakeEnum.TO_AREA.getType().equals(robotTaskVo.getTakeType())) {
                query = WareHouseLocationDO.builder()
                        .areaId(robotTaskVo.getTakeId())
                        .locationEnable(LocationEnableEnum.YES.getType())
                        .locationLock(LocationLockEnum.YES.getType())
                        .locationUseStatus(LocationUseStatusEnum.YES.getType())
                        .build();
            }

            List<WareHouseLocationDO> stockList = locationMapper.selectLocations(query, toLocationIds, mapIds,
                    new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
            if (ObjectUtil.isEmpty(stockList)) {
                log.error("取货线库/区域为空或者已锁定或者机器人取放货区域受限制 :{}", robotTaskVo.toString());
                throw exception0(TASK_CREATE_FAIL.getCode(), "取货线库/区域为空或者已锁定或者机器人取放货区域受限制");
            }
            //判断取货库位是否存在未完成的任务
            Set<Long> stockLocationIds = stockList.stream().map(WareHouseLocationDO::getId).collect(Collectors.toSet());
            List<RobotTaskDetailDO> doingTasks = taskDetailMapper.queryDoingTaskByIds(stockLocationIds);
            if (ObjectUtil.isNotEmpty(doingTasks)) {
                log.error("取货线库/区域,存在未完成的任务 :{}", JSON.toJSONString(doingTasks));
                throw exception0(TASK_CREATE_FAIL.getCode(), "取货线库/区域,存在未完成的任务");
            }
            //查找空库位
            WareHouseLocationDO releaseQuery = null;
            if (ReleaseTakeEnum.TO_LANE.getType().equals(robotTaskVo.getReleaseType())) {
                if (ObjectUtil.isEmpty(laneIds) && ObjectUtil.isNotEmpty(skuInfo)) {
                    log.error("查不到此物料对应的线库区域 :{}", robotTaskVo.getReleaseId());
                    throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的线库区域");
                }
                releaseQuery = WareHouseLocationDO.builder()
                        .laneId(robotTaskVo.getReleaseId())
                        .locationEnable(LocationEnableEnum.YES.getType())
                        .locationLock(LocationLockEnum.YES.getType())
                        .locationUseStatus(LocationUseStatusEnum.NO.getType())
                        .build();
            } else if (ReleaseTakeEnum.TO_AREA.getType().equals(robotTaskVo.getReleaseType())) {
                if (ObjectUtil.isEmpty(areaIds) && ObjectUtil.isNotEmpty(skuInfo)) {
                    log.error("查不到此物料对应的区域库位 :{}", robotTaskVo.getReleaseId());
                    throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的区域库位");
                }
                releaseQuery = WareHouseLocationDO.builder()
                        .areaId(robotTaskVo.getReleaseId())
                        .locationEnable(LocationEnableEnum.YES.getType())
                        .locationLock(LocationLockEnum.YES.getType())
                        .locationUseStatus(LocationUseStatusEnum.NO.getType())
                        .build();
            }

            List<WareHouseLocationDO> releaseStockList = locationMapper.selectLocations(releaseQuery, toLocationIds, mapIds,
                    laneIds, areaIds, mapItemIds);
            if (ObjectUtil.isEmpty(releaseStockList) || releaseStockList.size() < stockList.size()) {
                log.error("放货线库/区域库位数量不足或者机器人取放货区域受限制 :{}", robotTaskVo.toString());
                throw exception0(TASK_CREATE_FAIL.getCode(), "放货线库/区域库位数量不足或者机器人取放货区域受限制");
            }
            Collections.reverse(releaseStockList);
            //赋值数据
            List<RobotTaskDetailAddVO> addTaskDetailList = getTaskDatail(stockList, releaseStockList, toLocationIds,
                    robotTaskVo, taskId, fromLocationIds);
            newTaskDetailList.addAll(addTaskDetailList);

        }

        createReqVO.setTaskDetailList(newTaskDetailList);

        if (ObjectUtil.isNotEmpty(fromLocationIds)) {
            toLocationIds.addAll(fromLocationIds);
        }
        return toLocationIds;
    }

    /**
     * 赋值数据
     *
     * @param stockList
     * @param releaseStockList
     * @param toLocationIds
     * @param robotTaskVo
     * @return
     */
    private List<RobotTaskDetailAddVO> getTaskDatail(List<WareHouseLocationDO> stockList,
                                                     List<WareHouseLocationDO> releaseStockList,
                                                     List<Long> toLocationIds, RobotTaskDetailAddVO robotTaskVo,
                                                     Long taskId, List<Long> fromLocationIds) {
        List<RobotTaskDetailAddVO> addTaskDetailList = new ArrayList<>();
        for (int i = 0; i < stockList.size(); i++) {
            RobotTaskDetailAddVO robotTaskDetailAddVo = new RobotTaskDetailAddVO();
            robotTaskDetailAddVo.setTaskType(robotTaskVo.getTaskType());
            robotTaskDetailAddVo.setReleaseType(robotTaskVo.getReleaseType());
            robotTaskDetailAddVo.setTakeType(robotTaskVo.getTakeType());
            robotTaskDetailAddVo.setTakeId(robotTaskVo.getTakeId());
            robotTaskDetailAddVo.setReleaseId(robotTaskVo.getReleaseId());
            robotTaskDetailAddVo.setRobotNo(robotTaskVo.getRobotNo());
            robotTaskDetailAddVo.setFromLocationNo(stockList.get(i).getLocationNo());
            robotTaskDetailAddVo.setFromLocationId(stockList.get(i).getId());
            robotTaskDetailAddVo.setToLocationNo(releaseStockList.get(i).getLocationNo());
            robotTaskDetailAddVo.setToLocationId(releaseStockList.get(i).getId());
            robotTaskDetailAddVo.setFromLaneId(stockList.get(i).getLaneId());
            robotTaskDetailAddVo.setToLaneId(releaseStockList.get(i).getLaneId());
            robotTaskDetailAddVo.setFromLocationNumber(stockList.get(i).getLocationNumber());
            robotTaskDetailAddVo.setFromMapItemId(stockList.get(i).getMapItemId());
            robotTaskDetailAddVo.setToMapItemId(releaseStockList.get(i).getMapItemId());
            robotTaskDetailAddVo.setToLocationNumber(releaseStockList.get(i).getLocationNumber());
            robotTaskDetailAddVo.setRobotTaskId(taskId);
            robotTaskDetailAddVo.setPriority(robotTaskVo.getPriority());
            robotTaskDetailAddVo.setFromLocationStorey(stockList.get(i).getLocationStorey());
            robotTaskDetailAddVo.setToLocationStorey(releaseStockList.get(i).getLocationStorey());
            addTaskDetailList.add(robotTaskDetailAddVo);

            toLocationIds.add(releaseStockList.get(i).getId());
            fromLocationIds.add(stockList.get(i).getId());
        }
        return addTaskDetailList;
    }

    /**
     * 设置放货和取货的id
     *
     * @param taskDetailList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public List<Long> setSingleLocationIdNo(List<RobotTaskDetailAddVO> taskDetailList, RobotTaskDO task,
                                            List<Long> laneIds, List<Long> areaIds) {
        //取货中的map_item_id， 此集合不能执行放货的任务
        List<Long> takeMapItemIds = taskDetailMapper.selectTakeMapItemIds();
        if (ObjectUtil.isEmpty(takeMapItemIds)) {
            takeMapItemIds = new ArrayList<>();
        }
        //放货中的map_item_id， 此集合不能执行取货的任务
        List<Long> releaseMapItemIds = taskDetailMapper.selectReleaseMapItemIds();
        if (ObjectUtil.isEmpty(releaseMapItemIds)) {
            releaseMapItemIds = new ArrayList<>();
        }

        /*if (znConfigConstant.getDoCycle()) {
            List<TaskCycleDO> taskCycleDOS = taskCycleMapper.selectList(new LambdaQueryWrapper<TaskCycleDO>());
            if (ObjectUtil.isNotEmpty(taskCycleDOS)) {
                List<Long> mapItemIds =
                        taskCycleDOS.stream().map(TaskCycleDO::getMapItemId).collect(Collectors.toList());
                takeMapItemIds.addAll(mapItemIds);
                releaseMapItemIds.addAll(mapItemIds);
            }
        }*/
        List<WareHouseLocationDO> wareHouseLocationDOS = locationMapper.selectList(new LambdaQueryWrapper<WareHouseLocationDO>()
                .eq(WareHouseLocationDO::getLocationEnable, LocationEnableEnum.NO.getType()));
        if (ObjectUtil.isNotEmpty(wareHouseLocationDOS)) {
            List<Long> mapItemList = wareHouseLocationDOS.stream().map(WareHouseLocationDO::getMapItemId)
                    .collect(Collectors.toList());
            releaseMapItemIds.addAll(mapItemList);
        }
        List<Long> locationIds = new ArrayList<>();
        Set<Long> chooseLocationIds = new HashSet<>();

        for (RobotTaskDetailAddVO item : taskDetailList) {
            if (RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(item.getTaskType())) {
                chooseLocationIds.add(item.getTakeId());
                chooseLocationIds.add(item.getReleaseId());
            } else if (RobotTaskTypeEnum.TAKE.getType().equals(item.getTaskType())) {
                chooseLocationIds.add(item.getTakeId());
            } else if (RobotTaskTypeEnum.RELEASE.getType().equals(item.getTaskType())) {
                chooseLocationIds.add(item.getReleaseId());
            }
        }

        for (RobotTaskDetailAddVO robotTaskVo : taskDetailList) {
            robotTaskVo.setRobotTaskId(task.getId());
            robotTaskVo.setPriority(task.getPriority());
            RobotTaskTypeEnum robotTaskType = RobotTaskTypeEnum.getRobotTaskType(robotTaskVo.getTaskType());
            if (ObjectUtil.isEmpty(robotTaskType)) {
                throw exception0(TASK_CREATE_FAIL.getCode(), "任务类型不存在");
            }
            switch (robotTaskType) {
                case TAKE_RELEASE:
                    doTakeRelease(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds, laneIds, areaIds, task.getSkuInfo(), chooseLocationIds);
                    break;
                case PARK:
                    doPark(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds);
                    break;
                case CHARGE:
                    doCharge(robotTaskVo, takeMapItemIds, releaseMapItemIds);
                    break;
                case MOVE:
                    doMove(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds);
                    break;
                case TAKE:
                    doTake(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds, chooseLocationIds);
                    break;
                case RELEASE:
                    doRelease(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds, laneIds, areaIds, task.getSkuInfo(), chooseLocationIds);
                    break;
                case SCAN:
                    //暂无此功能
                    doScan(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds);
                    break;
                case DETECTING_TRAYS:
                    //暂无此功能
                    doDetectingTrays(robotTaskVo, locationIds, takeMapItemIds, releaseMapItemIds);
                    break;
                case MOVE_TO_POINT:
                    doMoveToPoint(robotTaskVo);
                    break;
                default:
                    log.error("任务类型不存在 ");
                    throw exception0(TASK_CREATE_FAIL.getCode(), "任务类型不存在");
            }
        }
        return locationIds;
    }

    /**
     * 移动到指定点位
     *
     * @param robotTaskVo
     */
    private void doMoveToPoint(RobotTaskDetailAddVO robotTaskVo) {
        PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(robotTaskVo.getReleaseId());
        robotTaskVo.setToLocationNo(String.valueOf(positionMapItem.getSortNum()));
    }

    /**
     * 检测托盘类型
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doDetectingTrays(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds, List<Long> takeMapItemIds,
                                 List<Long> releaseMapItemIds) {
        /*setToLocation(robotTaskVo,getMapIdsByRobotNo(robotTaskVo.getRobotNo()),new ArrayList<>());
        locationIds.add(robotTaskVo.getToLocationId());*/
    }

    /**
     * 扫描码
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doScan(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds, List<Long> takeMapItemIds,
                       List<Long> releaseMapItemIds) {
        /*setToLocation(robotTaskVo,getMapIdsByRobotNo(robotTaskVo.getRobotNo()),new ArrayList<>());
        locationIds.add(robotTaskVo.getToLocationId());*/
    }

    /**
     * 仅放货
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doRelease(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds, List<Long> takeMapItemIds,
                          List<Long> releaseMapItemIds, List<Long> laneIds, List<Long> areaIds, String skuInfo,
                          Set<Long> chooseLocationIds) {
        setToLocation(robotTaskVo, getMapIdsByRobotNo(robotTaskVo.getRobotNo()), locationIds, takeMapItemIds,
                releaseMapItemIds, laneIds, areaIds, skuInfo, chooseLocationIds);
        locationIds.add(robotTaskVo.getToLocationId());
    }

    /**
     * 仅取货
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doTake(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds, List<Long> takeMapItemIds,
                       List<Long> releaseMapItemIds, Set<Long> chooseLocationIds) {
        Set<Long> mapIds = new HashSet<>();
        if (ObjectUtil.isNotEmpty(robotTaskVo.getRobotNo())) {
            mapIds = getMapIdsByRobotNo(robotTaskVo.getRobotNo());
        }
        setFromLocation(robotTaskVo, mapIds, locationIds, takeMapItemIds, releaseMapItemIds, chooseLocationIds);
        locationIds.add(robotTaskVo.getFromLocationId());
    }

    /**
     * 移动
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doMove(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds, List<Long> takeMapItemIds,
                       List<Long> releaseMapItemIds) {
        setToLocation(robotTaskVo, getMapIdsByRobotNo(robotTaskVo.getRobotNo()), locationIds, takeMapItemIds, releaseMapItemIds,
                null, null, null, null);
        locationIds.add(robotTaskVo.getToLocationId());
    }

    /**
     * 充电
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doCharge(RobotTaskDetailAddVO robotTaskVo, List<Long> takeMapItemIds,
                         List<Long> releaseMapItemIds) {

    }

    /**
     * 停车
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doPark(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds, List<Long> takeMapItemIds,
                       List<Long> releaseMapItemIds) {
        // todo 停车后续停到等待点
        /*setToLocation(robotTaskVo,getMapIdsByRobotNo(robotTaskVo.getRobotNo()),locationIds);
        locationIds.add(robotTaskVo.getToLocationId());*/
    }

    /**
     * 查询此机器人对应的楼层/区域(json)
     *
     * @param robotNo
     * @return
     */
    public Set<Long> getMapIdsByRobotNo(String robotNo) {
        if (ObjectUtil.isNotEmpty(robotNo)) {
            RobotInformationPageReqVO pageReqVO = new RobotInformationPageReqVO();
            pageReqVO.setRobotNo(robotNo);
            return informationMapper.selectPage(pageReqVO).getList()
                    .stream()
                    .findFirst()
                    .map(RobotInformationDO::getFloorAreaJson)
                    .orElse(new HashSet<>());
        }
        return new HashSet<>();
    }

    /**
     * 设置停车/目标库位/扫描库位
     */
    @Transactional(rollbackFor = Exception.class)
    public void setToLocation(RobotTaskDetailAddVO robotTaskVo, Set<Long> mapIds, List<Long> locationIds,
                              List<Long> takeMapItemIds, List<Long> releaseMapItemIds,
                              List<Long> laneIds, List<Long> areaIds, String skuInfo, Set<Long> chooseLocationIds) {
        if (ReleaseTakeEnum.TO_LOCATION.getType().equals(robotTaskVo.getReleaseType())) {
            WareHouseLocationDO query = WareHouseLocationDO.builder().id(robotTaskVo.getReleaseId()).build();
            WareHouseLocationDO locationDO = locationMapper.queryAllByLimit(query);
            robotTaskVo.setToLocationNo(locationDO.getLocationNo());
            robotTaskVo.setToLocationId(robotTaskVo.getReleaseId());
            robotTaskVo.setToLocationStorey(locationDO.getLocationStorey());
            robotTaskVo.setToLaneId(locationDO.getLaneId());
            robotTaskVo.setToLocationNumber(locationDO.getLocationNumber());
            robotTaskVo.setToMapItemId(locationDO.getMapItemId());
            if (ObjectUtil.isNotEmpty(mapIds) && !mapIds.contains(locationDO.getMapId())) {
                log.error("机器人不能在此放货库位放货 :{}, 机器人编号 :{}", locationDO.getLocationNo(), robotTaskVo.getRobotNo());
                throw exception0(TASK_CREATE_FAIL.getCode(), "车辆不能在此放货库位放货,检查车辆能走的区域 " + robotTaskVo.getRobotNo());
            }
            if (ObjectUtil.isNotEmpty(takeMapItemIds) && takeMapItemIds.contains(locationDO.getMapItemId())) {
                log.error("此点位存在取货任务 :{}", locationDO.getLocationNo());
                throw exception0(TASK_CREATE_FAIL.getCode(), "此库位存在取货任务 " + locationDO.getLocationNo());
            }
            if (LocationUseStatusEnum.YES.getType().equals(locationDO.getLocationUseStatus())) {
                log.error("此放货库位有库存 :{}", locationDO.getLocationNo());
                throw exception0(TASK_CREATE_FAIL.getCode(), "此放货库位有库存 " + locationDO.getLocationNo());
            }
            checkToLocationNoneTask(locationDO, chooseLocationIds);
            releaseMapItemIds.add(locationDO.getMapItemId());
        } else if (ReleaseTakeEnum.TO_POINT.getType().equals(robotTaskVo.getReleaseType())) {
            WareHouseTakePointDO houseTakePoint = houseTakePointService.getHouseTakePoint(robotTaskVo.getReleaseId());
            if (ZeroOneEnum.ONE.getType().equals(houseTakePoint.getPointStatus())) {
                throw exception0(TASK_CREATE_FAIL.getCode(), "此放货点位有库存 " + houseTakePoint.getPointName());
            }
            robotTaskVo.setToLocationNo(houseTakePoint.getPointName());
            robotTaskVo.setToLocationId(robotTaskVo.getTakeId());
            robotTaskVo.setToLocationStorey(houseTakePoint.getLocationStorey());
            robotTaskVo.setToLaneId(houseTakePoint.getLaneId());
            robotTaskVo.setToLocationNumber(houseTakePoint.getLocationNumber());
            robotTaskVo.setToMapItemId(houseTakePoint.getPositionMapItemId());
        } else {
            if (ReleaseTakeEnum.TO_LANE.getType().equals(robotTaskVo.getReleaseType()) && ObjectUtil.isEmpty(laneIds)
                    && ObjectUtil.isNotEmpty(skuInfo)) {
                log.error("查不到此物料对应的线库区域 :{}", robotTaskVo.getReleaseId());
                throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的线库区域 " + skuInfo);
            }
            if (ReleaseTakeEnum.TO_AREA.getType().equals(robotTaskVo.getReleaseType()) && ObjectUtil.isEmpty(areaIds)
                    && ObjectUtil.isNotEmpty(skuInfo)) {
                log.error("查不到此物料对应的区域库位 :{}", robotTaskVo.getReleaseId());
                throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的区域库位 " + skuInfo);
            }
            WareHouseLocationDO wareHouseLocationDO =
                    locationMapper.selectByTypeAndId(LocationUseStatusEnum.NO.getType(), robotTaskVo.getReleaseType()
                            , robotTaskVo.getReleaseId(), locationIds, mapIds, takeMapItemIds, laneIds, areaIds);
            if (ObjectUtil.isEmpty(wareHouseLocationDO)) {
                log.error("放货库位为空或者已锁定或者机器人取放货区域受限制 :{}", robotTaskVo.getReleaseId());
                throw exception0(TASK_CREATE_FAIL.getCode(), "放货库位为空或者已锁定或者机器人取放货区域受限制 " + robotTaskVo.getReleaseId());
            }
            robotTaskVo.setToLocationNo(wareHouseLocationDO.getLocationNo());
            robotTaskVo.setToLocationId(wareHouseLocationDO.getId());
            robotTaskVo.setToLocationStorey(wareHouseLocationDO.getLocationStorey());
            robotTaskVo.setToLaneId(wareHouseLocationDO.getLaneId());
            robotTaskVo.setToLocationNumber(wareHouseLocationDO.getLocationNumber());
            robotTaskVo.setToMapItemId(wareHouseLocationDO.getMapItemId());
            releaseMapItemIds.add(wareHouseLocationDO.getMapItemId());
        }
    }

    /**
     * 校验放货库位的下一层是否没任务
     *
     * @param locationDO
     */
    private void checkToLocationNoneTask(WareHouseLocationDO locationDO, Set<Long> chooseLocationIds) {
        if (ObjectUtil.isEmpty(chooseLocationIds)) {
            return;
        }
        List<Long> locations = locationMapper.queryLowerLevelsByMapItemId(locationDO.getMapItemId(), locationDO.getLocationStorey());

        if (ObjectUtil.isEmpty(locations) || chooseLocationIds.containsAll(locations)) {
            return;
        }

        log.error("此放货库位的下层库位无货,请先放下层库位 :{}", locationDO.getLocationNo());
        throw exception0(TASK_CREATE_FAIL.getCode(), "此放货库位的下层库位无货,请先放下层库位 " + locationDO.getLocationNo());
    }

    /**
     * 设置取货库位
     *
     * @param robotTaskVo
     * @param mapIds
     * @param locationIds
     */
    @Transactional(rollbackFor = Exception.class)
    public void setFromLocation(RobotTaskDetailAddVO robotTaskVo, Set<Long> mapIds, List<Long> locationIds,
                                List<Long> takeMapItemIds, List<Long> releaseMapItemIds, Set<Long> chooseLocationIds) {
        if (ReleaseTakeEnum.TO_LOCATION.getType().equals(robotTaskVo.getTakeType())) {
            WareHouseLocationDO query = WareHouseLocationDO.builder().id(robotTaskVo.getTakeId()).build();
            WareHouseLocationDO locationDO = locationMapper.queryAllByLimit(query);
            robotTaskVo.setFromLocationNo(locationDO.getLocationNo());
            robotTaskVo.setFromLocationId(robotTaskVo.getTakeId());
            robotTaskVo.setFromLocationStorey(locationDO.getLocationStorey());
            robotTaskVo.setFromLaneId(locationDO.getLaneId());
            robotTaskVo.setFromLocationNumber(locationDO.getLocationNumber());
            robotTaskVo.setFromMapItemId(locationDO.getMapItemId());
            if (ObjectUtil.isNotEmpty(mapIds) && !mapIds.contains(locationDO.getMapId())) {
                log.error("机器人不能在此取货库位取货 :{}, 机器人编号 :{}", locationDO.getLocationNo(), robotTaskVo.getRobotNo());
                throw exception0(TASK_CREATE_FAIL.getCode(), "机器人不能在此取货库位取货 " + robotTaskVo.getTakeId());
            }
            if (ObjectUtil.isNotEmpty(releaseMapItemIds) && releaseMapItemIds.contains(locationDO.getMapItemId())) {
                log.error("此取货库位存在放货任务 :{}", locationDO.getLocationNo());
                throw exception0(TASK_CREATE_FAIL.getCode(), "此取货库位存在放货任务 " + locationDO.getLocationNo());
            }
            if (LocationUseStatusEnum.NO.getType().equals(locationDO.getLocationUseStatus())) {
                log.error("此取货库位没库存 :{}", locationDO.getLocationNo());
                throw exception0(TASK_CREATE_FAIL.getCode(), "此取货库位没库存 " + locationDO.getLocationNo());
            }
            checkFromLocationNoneTask(locationDO, chooseLocationIds);
            takeMapItemIds.add(locationDO.getMapItemId());
        } else if (ReleaseTakeEnum.TO_POINT.getType().equals(robotTaskVo.getTakeType())) {
            WareHouseTakePointDO houseTakePoint = houseTakePointService.getHouseTakePoint(robotTaskVo.getTakeId());
            if (ZeroOneEnum.ZERO.getType().equals(houseTakePoint.getPointStatus())) {
                throw exception0(TASK_CREATE_FAIL.getCode(), "此取货点位没库存 " + houseTakePoint.getPointName());
            }
            robotTaskVo.setFromLocationNo(houseTakePoint.getPointName());
            robotTaskVo.setFromLocationId(robotTaskVo.getTakeId());
            robotTaskVo.setFromLocationStorey(houseTakePoint.getLocationStorey());
            robotTaskVo.setFromLaneId(houseTakePoint.getLaneId());
            robotTaskVo.setFromLocationNumber(houseTakePoint.getLocationNumber());
            robotTaskVo.setFromMapItemId(houseTakePoint.getPositionMapItemId());
        } else {
            WareHouseLocationDO wareHouseLocationDO =
                    locationMapper.selectByTypeAndId(LocationUseStatusEnum.YES.getType(), robotTaskVo.getTakeType(),
                            robotTaskVo.getTakeId(), locationIds, mapIds, releaseMapItemIds, new ArrayList<>(), new ArrayList<>());
            if (ObjectUtil.isEmpty(wareHouseLocationDO)) {
                log.error("取货库位为空或者已锁定或者机器人取放货区域受限制 :{}", robotTaskVo.getTakeId());
                throw exception0(TASK_CREATE_FAIL.getCode(), "取货库位为空或者已锁定或者机器人取放货区域受限制 " + robotTaskVo.getTakeId());
            }
            robotTaskVo.setFromLocationNo(wareHouseLocationDO.getLocationNo());
            robotTaskVo.setFromLocationId(wareHouseLocationDO.getId());
            robotTaskVo.setFromLocationStorey(wareHouseLocationDO.getLocationStorey());
            robotTaskVo.setFromLaneId(wareHouseLocationDO.getLaneId());
            robotTaskVo.setFromLocationNumber(wareHouseLocationDO.getLocationNumber());
            robotTaskVo.setFromMapItemId(wareHouseLocationDO.getMapItemId());
            takeMapItemIds.add(wareHouseLocationDO.getMapItemId());
        }
    }

    /**
     * 校验取货库位的上层是否存在未取的箱子
     *
     * @param locationDO
     */
    private void checkFromLocationNoneTask(WareHouseLocationDO locationDO, Set<Long> chooseLocationIds) {

        if (ObjectUtil.isEmpty(chooseLocationIds)) {
            return;
        }

        List<Long> locations = locationMapper.queryUpperLevelsByMapItemId(locationDO.getMapItemId(), locationDO.getLocationStorey());
        if (ObjectUtil.isEmpty(locations) || chooseLocationIds.containsAll(locations)) {
            return;
        }

        log.error("此取货库位的上层库位有货,请先取上层库位的货物 :{}", locationDO.getLocationNo());
        throw exception0(TASK_CREATE_FAIL.getCode(), "此取货库位的上层库位有货,请先取上层库位的货物 " + locationDO.getLocationNo());
    }

    /**
     * 取放
     *
     * @param robotTaskVo
     */
    @Transactional(rollbackFor = Exception.class)
    public void doTakeRelease(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds,
                              List<Long> takeMapItemIds, List<Long> releaseMapItemIds,
                              List<Long> laneIds, List<Long> areaIds, String skuInfo, Set<Long> chooseLocationIds) {
        Set<Long> mapIds = new HashSet<>();
        if (ObjectUtil.isNotEmpty(robotTaskVo.getRobotNo())) {
            mapIds = getMapIdsByRobotNo(robotTaskVo.getRobotNo());
        }

        //校验放货库位
        setToLocation(robotTaskVo, mapIds, locationIds, takeMapItemIds, releaseMapItemIds, laneIds, areaIds, skuInfo, chooseLocationIds);
        locationIds.add(robotTaskVo.getToLocationId());

        //校验取货库位
        setFromLocation(robotTaskVo, mapIds, locationIds, takeMapItemIds, releaseMapItemIds, chooseLocationIds);
        locationIds.add(robotTaskVo.getFromLocationId());

        //验证取货库位是否存在未完成的任务
        Set<Long> set = new HashSet<>();
        set.add(robotTaskVo.getFromLocationId());
        List<RobotTaskDetailDO> doingTasks = taskDetailMapper.queryDoingTaskByIds(set);
        if (ObjectUtil.isNotEmpty(doingTasks)) {
            log.error("取货库位,存在未完成的任务 :{}", robotTaskVo.getTakeId());
            throw exception0(TASK_CREATE_FAIL.getCode(), "取货库位,存在未完成的任务");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTask(RobotTaskSaveReqVO updateReqVO) {

        // 校验存在
        validateTaskExists(updateReqVO.getId());
        if (ObjectUtil.isEmpty(updateReqVO.getId())) {
            throw exception(TASK_CHECK_ID_EXCEPTION);
        }
        // 更新
        //修改优先级需要订单状态为未开始/处理中
        RobotTaskDO robotTaskDO = taskMapper.selectById(updateReqVO.getId());
        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.queryByTaskId(updateReqVO.getId());
        if (ObjectUtil.isNotEmpty(updateReqVO.getPriority())
                && !updateReqVO.getPriority().equals(robotTaskDO.getPriority())) {
            /*if (!RobotTaskStatusEnum.NEW.getType().equals(robotTaskDO.getTaskStatus())
                    && !RobotTaskStatusEnum.DOING.getType().equals(robotTaskDO.getTaskStatus())) {
                throw exception(TASK_CHECK_TASK_PRIORITY);
            }*/
            for (RobotTaskDetailDO taskDetailDO : taskDetailDOS) {
                taskDetailDO.setPriority(updateReqVO.getPriority());
            }
        }

        RobotTaskDO updateObj = BeanUtils.toBean(updateReqVO, RobotTaskDO.class);
        taskMapper.updateById(updateObj);

        taskDetailMapper.updateById(taskDetailDOS);

        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                .operateAction("修改" + robotTaskDO.getTaskNo() + "优先级" + updateReqVO.getPriority())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);
    }

    @Override
    public void deleteTask(Long id) {
        // 校验存在
        validateTaskExists(id);
        // 删除
        taskMapper.deleteById(id);
    }

    private void validateTaskExists(Long id) {
        if (taskMapper.selectById(id) == null) {
            throw exception(TASK_NOT_EXISTS);
        }
    }

    @Override
    public RobotTaskDO getTask(Long id) {
        return taskMapper.selectById(id);
    }

    @Override
    public PageResult<RobotTaskRespVO> getTaskPage(RobotTaskPageReqVO pageReqVO) {

        PageResult<RobotTaskDO> pageResult = null;
        PageResult<RobotTaskRespVO> dataPage = new PageResult<>();
        List<RobotTaskDO> list = new ArrayList<>();
        if (ObjectUtil.isEmpty(pageReqVO.getRobotNo()) && ObjectUtil.isEmpty(pageReqVO.getTaskStage())) {
            pageResult = taskMapper.selectPage(pageReqVO);
            dataPage.setTotal(pageResult.getTotal());
            list = pageResult.getList();
        } else {
            IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
            IPage<RobotTaskDO> page = taskMapper.selectPageList(mpPage, pageReqVO);
            dataPage.setTotal(page.getTotal());
            list = page.getRecords();
        }

        List<RobotTaskRespVO> targetList = BeanUtil.copyToList(list, RobotTaskRespVO.class);
        if (ObjectUtil.isEmpty(targetList)) {
            return dataPage;
        }

        List<Long> takeIds = targetList.stream().map(RobotTaskRespVO::getId).collect(Collectors.toList());
        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.selectList(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                .in(RobotTaskDetailDO::getRobotTaskId, takeIds));

        Map<Long, List<RobotTaskDetailDO>> detailMap = taskDetailDOS.stream().collect(Collectors.groupingBy(RobotTaskDetailDO::getRobotTaskId));

        for (RobotTaskRespVO v : targetList) {
            List<RobotTaskDetailDO> details = detailMap.get(v.getId());
            if (ObjectUtil.isNotEmpty(pageReqVO.getTaskStage())) {
                details = details.stream()
                        .filter(s -> s.getTaskStage().equals(pageReqVO.getTaskStage()))
                        .collect(Collectors.toList());
            }
            v.setDetails(details);
        }
        dataPage.setList(targetList);
        return dataPage;
    }

    @Override
    public String getTaskNo() {
        String incrementByKey = redisUtil.getIncrementByKey(RobotCacheLockEnum.TASK_NO.getKey());
        return znConfigConstant.getTaskNo() + DateUtils.getYearMonthDay() + incrementByKey;
    }

    /**
     * PP分配的任务(此方法已经废弃)
     *
     * @param message
     */
   /* @Override
    @Deprecated
    @Transactional(rollbackFor = Exception.class)
    public void ppDistributionTask(String message) {
        log.info("PP分配任务 :{}", message);

        TaskPPDistribution distribution = JSON.parseObject(message, TaskPPDistribution.class);
        String mac = robotInformationService.getMacByRobotNo(distribution.getRobotNo());
        String robotDoingActionKey = RobotTaskChcheConstant.ROBOT_QUERY_DOING_ACTION + mac;
        redisUtil.del(robotDoingActionKey);

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

        Map<Long, String> deviceNoMap = new HashMap<>();
        RobotChargeLogDO robotChargeLogs = null;

        *//**
     * 充电
     *//*
        if (TaskTypeEnum.CHARGE.getType().equals(distribution.getType())) {
            robotChargeLogs = chargeLogMapper.selectById(distribution.getId());

            robotChargeLogs.setTaskStatus(ChargeTaskStatusEnum.DOING.getType());
            chargeLogMapper.updateById(robotChargeLogs);

            robotInformationMapper.updateRobotListStatus(distribution.getRobotNo(), RobotStatusEnum.CHARGE.getType(), distribution.getId());
            if (ObjectUtil.isNotEmpty(robotChargeLogs.getTaskDetailId())) {
                deviceNoMap.put(robotChargeLogs.getTaskDetailId(), robotChargeLogs.getDeviceNo());
                detailIds.add(robotChargeLogs.getTaskDetailId());
            }
        }

        *//**
     * 任务
     *//*
        if (TaskTypeEnum.TASK.getType().equals(distribution.getType())) {
            chargeDone(distribution.getRobotNo());
            robotInformationMapper.updateRobotListStatus(distribution.getRobotNo(), RobotStatusEnum.DOING.getType(), distribution.getId());
            detailIds.add(distribution.getId());
        }

        if (ObjectUtil.isNotEmpty(detailIds)) {
            List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.selectBatchIds(detailIds);
            taskDetailDOS.stream().forEach(taskDetailDO -> {
                taskDetailDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
                taskDetailDO.setStartTime(LocalDateTime.now());
                if (ObjectUtil.isEmpty(taskDetailDO.getRobotNo())) {
                    taskDetailDO.setRobotNo(distribution.getRobotNo());
                }
                if (ObjectUtil.isEmpty(taskDetailDO.getToLocationNo())
                        && ObjectUtil.isNotEmpty(deviceNoMap.get(taskDetailDO.getId()))) {
                    taskDetailDO.setToLocationNo(deviceNoMap.get(taskDetailDO.getId()));
                }
            });

            taskDetailMapper.updateById(taskDetailDOS);
            List<Long> robotTaskIds = taskDetailDOS.stream()
                    .map(RobotTaskDetailDO::getRobotTaskId)
                    .collect(Collectors.toList());
            List<RobotTaskDO> tasks = taskMapper.selectBatchIds(robotTaskIds);
            tasks.stream().forEach(task -> {
                task.setTaskStatus(RobotTaskStatusEnum.DOING.getType());
            });
            taskMapper.updateById(tasks);
        }

        if (TaskTypeEnum.TASK.getType().equals(distribution.getType())) {
            robotCommonTaskService.sendTaskToRobot(distribution);
        } else if (TaskTypeEnum.CHARGE.getType().equals(distribution.getType())) {
            robotCommonTaskService.sendChargeTaskToRobot(distribution, robotChargeLogs);
        }

    }*/

    /**
     * 机器人完成充电
     *
     * @param robotNo
     */
    @Override
    public void chargeDone(String robotNo) {
        RobotInformationDO robotInformationDO = robotInformationMapper.selectOne(new LambdaQueryWrapperX<RobotInformationDO>()
                .eq(RobotInformationDO::getRobotNo, robotNo));
        if (!RobotStatusEnum.CHARGE.getType().equals(robotInformationDO.getRobotStatus())) {
            log.info("车辆非充电状态:{}", robotNo);
            return;
        }

        RobotChargeLogDO robotChargeLogDO = chargeLogMapper.selectOne(new LambdaQueryWrapperX<RobotChargeLogDO>()
                .eq(RobotChargeLogDO::getRobotNo, robotNo)
                .orderByDesc(RobotChargeLogDO::getCreateTime)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(robotChargeLogDO) || !ChargeTaskStatusEnum.CHARGEING.getType().equals(robotChargeLogDO.getTaskStatus())) {
            return;
        }

        DeviceInformationDO deviceInformationDO = deviceInformationMapper.selectOne(new LambdaQueryWrapperX<DeviceInformationDO>()
                .eq(DeviceInformationDO::getLastUser, robotNo)
                .eq(DeviceInformationDO::getDeviceNo, robotChargeLogDO.getDeviceNo()));

        log.info("结束充电任务 :{}", robotNo);
        robotChargeLogDO.setEndTime(LocalDateTime.now());
        if (ObjectUtil.isNotEmpty(deviceInformationDO)) {
            log.info("充电桩设置为空闲 :{}", deviceInformationDO.getDeviceNo());
            deviceInformationService.chargeDeviceShrink(robotChargeLogDO.getDeviceNo());
            deviceInformationDO.setDeviceUseStatus(DeviceUseStatusEnum.IDLE.getType());
            deviceInformationDO.setLastUser(null);
            deviceInformationMapper.updateById(deviceInformationDO);
        }

        String socKey = RobotTaskChcheConstant.ROBOT_INFORMATION_SOC + robotInformationDO.getMacAddress();
        Object socObject = redisUtil.get(socKey);

        if (ObjectUtil.isNotEmpty(socObject)) {
            robotChargeLogDO.setEndElectricity(Integer.valueOf(socObject.toString()));
        }
        robotChargeLogDO.setTaskStatus(ChargeTaskStatusEnum.DONE.getType());
        chargeLogMapper.updateById(robotChargeLogDO);

        if (ObjectUtil.isEmpty(robotChargeLogDO.getTaskDetailId())) {
            return;
        }
        RobotTaskDetailDO taskDetail = taskDetailMapper.selectById(robotChargeLogDO.getTaskDetailId());
        if (ObjectUtil.isNotEmpty(taskDetail) && RobotTaskTypeEnum.CHARGE.getType().equals(taskDetail.getTaskType())) {
            taskDetail.setTaskStatus(RobotTaskDetailStatusEnum.DONE.getType());
            taskDetailMapper.updateById(taskDetail);
            RobotTaskDO robotTask = taskMapper.selectById(taskDetail.getRobotTaskId());
            robotTask.setTaskStatus(RobotTaskStatusEnum.DONE.getType());
            taskMapper.updateById(robotTask);
        }
    }

    @Override
    public Integer getRobotTaskNum(String robotNo) {
        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.selectList(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                .eq(RobotTaskDetailDO::getRobotNo, robotNo)
                .ne(RobotTaskDetailDO::getTaskStatus, RobotTaskStatusEnum.NEW.getType()));

        return ObjectUtil.isEmpty(taskDetailDOS) ? 0 : taskDetailDOS.size();
    }

    /**
     * 任务日志分页
     *
     * @param pageReqVO
     * @return
     */
    @Override
    public PageResult<RobotTaskDetailLogResoVO> logPage(RobotTaskDetailLogVO pageReqVO) {
        PageResult<RobotTaskDetailLogResoVO> dataPage = new PageResult<>();

        IPage mpPage = MyBatisUtils.buildPage(pageReqVO);

        IPage<RobotTaskDetailLogResoVO> page = taskMapper.selectLogPageList(mpPage, pageReqVO);
        dataPage.setTotal(page.getTotal());
        List<RobotTaskDetailLogResoVO> list = page.getRecords();

        List<RobotTaskDetailLogResoVO> targetList = BeanUtil.copyToList(list, RobotTaskDetailLogResoVO.class);
        for (RobotTaskDetailLogResoVO robotTaskRespVO : targetList) {
            String msg = "";
            RobotTaskTypeEnum robotTaskType = RobotTaskTypeEnum.getRobotTaskType(robotTaskRespVO.getTaskType());
            switch (robotTaskType) {
                case TAKE_RELEASE:
                    msg = "取货点 " + robotTaskRespVO.getFromLocationNo() + " 放货点 " + robotTaskRespVO.getToLocationNo();
                    break;
                case PARK:
                    if (ObjectUtil.isNotEmpty(robotTaskRespVO.getToLocationNo())) {
                        msg = "停车点 " + robotTaskRespVO.getToLocationNo();
                    } else {
                        msg = "停车点";
                    }
                    break;
                case CHARGE:
                    if (ObjectUtil.isNotEmpty(robotTaskRespVO.getToLocationNo())) {
                        msg = "充电点 " + robotTaskRespVO.getToLocationNo();
                    } else {
                        msg = "充电点";
                    }
                    break;
                case MOVE:
                    if (ObjectUtil.isNotEmpty(robotTaskRespVO.getToLocationNo())) {
                        msg = "移动点 " + robotTaskRespVO.getToLocationNo();
                    } else {
                        msg = "移动点";
                    }
                    break;
                case TAKE:
                    msg = "取货点 " + robotTaskRespVO.getFromLocationNo();
                    break;
                case RELEASE:
                    msg = "放货点 " + robotTaskRespVO.getToLocationNo();
                    break;
                case MOVE_TO_POINT:
                    msg = "移动到点位 " + robotTaskRespVO.getToLocationNo();
                    break;
                default:
                    log.error("任务类型不存在");
            }

            robotTaskRespVO.setMsg(msg);
        }
        dataPage.setList(targetList);
        return dataPage;
    }


}
