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

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.system.api.path.vo.RobotClosePathPlantingDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotCommandStateDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotCompleteTaskDTO;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotSkuInfoDTO;
import cn.iocoder.yudao.module.system.api.robot.websocket.WsWareHouseLocationDTO;
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.CommonConstant;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningChcheConstant;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningTopicConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotExecutionStateConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.RobotTaskDetailActionLogSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseTakePointDO;
import cn.iocoder.yudao.module.system.dal.dataobject.log.RobotTaskDetailActionLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.*;
import cn.iocoder.yudao.module.system.dal.mysql.log.RobotTaskDetailActionLogMapper;
import cn.iocoder.yudao.module.system.dal.mysql.cycle.TaskCycleMapper;
import cn.iocoder.yudao.module.system.dal.mysql.houselocation.WareHouseLocationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.*;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.path.PathIsReachEnum;
import cn.iocoder.yudao.module.system.enums.path.PathTaskTypeEnum;
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.charge.ChargeTaskStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotStatusCodeEnum;
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.path.PathPlanningService;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskDetailService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

@Slf4j
@RestController // 提供 RESTful API 接口，给 Feign 调用
@Validated
public class RobotTaskStatusApiImpl implements RobotTaskStatusApi {

    @Autowired
    private RobotTaskDetailMapper robotTaskDetailMapper;

    @Autowired
    private RobotTaskMapper robotTaskMapper;

    @Autowired
    @Resource
    private RobotInformationMapper robotInformationMapper;

    @Resource
    private RobotTaskDetailActionLogMapper taskDetailActionLogMapper;

    @Resource
    private RobotTaskDetailActionLogService taskDetailActionLogService;

    @Autowired
    private RobotInformationService robotInformationService;

    @Resource
    private RedisUtil redisUtil;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private TaskCycleMapper taskCycleMapper;

    @Resource
    private WareHouseLocationMapper locationMapper;

    @Resource
    private RobotChargeLogMapper chargeLogMapper;

    /*@Resource
    private CommonApi commonApi;*/

    @Autowired
    private MqttUtils mqttUtils;

    @Resource
    public WebSocketSenderApi webSocketSenderApi;

    @Resource
    private RobotTaskDetailService taskDetailService;

    @Resource
    private RobotWarnMsgMapper warnMsgMapper;

    @Resource
    private RobotWarnMsgService warnMsgService;

    @Resource
    private PathPlanningService pathPlanningService;

    @Resource
    private DeviceInformationService deviceInformationService;

    @Resource
    private WareHouseTakePointService houseTakePointService;

    @Resource
    private TaskDistributionProducer taskDistributionProducer;

    @Autowired
    private ZnConfigConstant znConfigConstant;

    @Transactional(rollbackFor = Exception.class)
    public void doRobotDoneTask(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        log.info("111111机器人完成任务上报 :{}", JSON.toJSONString(robotCompleteTaskDTO));
        TenantContextHolder.setTenantId(1L);
        String robotDoingActionKey = RobotTaskChcheConstant.ROBOT_QUERY_DOING_ACTION + robotCompleteTaskDTO.getMac();

        if (ObjectUtil.isEmpty(robotCompleteTaskDTO.getOrderId())) {
            log.info("没有任务id :{}", JSON.toJSONString(robotCompleteTaskDTO));
            return;
        }

        if (!RobotStatusCodeEnum.SUCCESS.getType().equals(robotCompleteTaskDTO.getStatusCode())) {
            log.info("车机上报异常 :{}", JSON.toJSONString(robotCompleteTaskDTO));
            //todo 取不了和放不了的异常
            redisUtil.del(robotDoingActionKey);
            closeTask(robotCompleteTaskDTO);
            return;
        }

        if (ObjectUtil.isNotEmpty(robotCompleteTaskDTO.getCommandStatus())
                && RobotExecutionStateConstant.UN_DO.equals(robotCompleteTaskDTO.getCommandStatus().getExecutionState())) {
            log.info("任务未开始 :{}", robotCompleteTaskDTO.getOrderId());
        } else if (RobotExecutionStateConstant.UN_DO.equals(robotCompleteTaskDTO.getExecutionState())
                || RobotExecutionStateConstant.STOP.equals(robotCompleteTaskDTO.getExecutionState())
                || RobotExecutionStateConstant.CLOSE.equals(robotCompleteTaskDTO.getExecutionState())) {
            log.info("任务未开始/暂停/取消 :{}", robotCompleteTaskDTO.getOrderId());
        } else if (RobotExecutionStateConstant.DONE.equals(robotCompleteTaskDTO.getExecutionState())) {
            robotTaskDone(robotCompleteTaskDTO);
            redisUtil.del(robotDoingActionKey);
            String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
            String freeTimeKey = RobotTaskChcheConstant.ROBOT_LAST_FREE_TIME + robotNo;
            String timeStr = DateUtils.getYearMonthDayHourMinuteSecon();
            redisUtil.set(freeTimeKey, timeStr);
        } else if (RobotExecutionStateConstant.DOING.equals(robotCompleteTaskDTO.getExecutionState())) {
            robotTaskDoing(robotCompleteTaskDTO, robotDoingActionKey);
        }
    }

    /**
     * 上一条明细设置为完成
     *
     * @return
     */
    public RobotTaskDetailActionLogDO setLastLogDone(Long orderId) {
        return taskDetailActionLogService.setPreviousTaskDoneByOrderId(orderId);
    }

    /**
     * @param robotCompleteTaskDTO
     */
    private void robotTaskDoing(RobotCompleteTaskDTO robotCompleteTaskDTO, String robotDoingActionKey) {

        taskDoing(robotCompleteTaskDTO, robotDoingActionKey);

        if ((PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType()))
                && ObjectUtil.isNotEmpty(robotCompleteTaskDTO.getCommandStatus())
                && CommandTypeEnum.MOVE_POSES.getType().equals(robotCompleteTaskDTO.getCommandStatus().getCommandType())
                && RobotExecutionStateConstant.DONE.equals(robotCompleteTaskDTO.getCommandStatus().getExecutionState())) {
            log.info("充电任务准备让充电设备自动伸出 :{}", robotCompleteTaskDTO.getOrderId());
            RobotChargeLogDO robotChargeLog = chargeLogMapper.selectById(robotCompleteTaskDTO.getOrderId());
            deviceInformationService.chargeDeviceExtend(robotChargeLog.getDeviceNo());
        }

        sendStartDoActionToPP(robotCompleteTaskDTO.getCommandStatus(), robotCompleteTaskDTO.getMac(),
                String.valueOf(robotCompleteTaskDTO.getOrderId()));

        taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DOING.getType()
                , null);

        if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            chargeDoing(robotCompleteTaskDTO);
        }
    }

    /**
     * 告诉PP开始作业
     *
     * @param commandStatus
     * @param mac
     * @param orderId
     */
    public void sendStartDoActionToPP(RobotCommandStateDTO commandStatus, String mac, String orderId) {
        if (ObjectUtil.isNotEmpty(commandStatus)
                || CommandTypeEnum.WORK_PICK_UP_GOODS_MOVE_TO_CHECK.getType().equals(commandStatus.getCommandType())
                || CommandTypeEnum.WORK_DROP_OFF_GOODS_MOVE_TO_CHECK.getType().equals(commandStatus.getCommandType())) {
            log.info("不发作业");
            return;
        }
        if (ObjectUtil.isNotEmpty(commandStatus) && RobotExecutionStateConstant.DOING.equals(commandStatus.getExecutionState())
                && !CommandTypeEnum.MOVE_POSES.getType().equals(commandStatus.getCommandType())) {
            String robotNo = robotInformationService.getRobotNoByMac(mac);
            pathPlanningService.updateBehavior(orderId, robotNo
                    , "", PathIsReachEnum.START_WORK.getType());
        }
    }

    /**
     * 机器人完成任务
     *
     * @param robotCompleteTaskDTO
     */
    private void robotTaskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        setLastLogDone(robotCompleteTaskDTO.getOrderId());

        //释放库位数据
        if (PathTaskTypeEnum.TAKE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())
                && CommandTypeEnum.WORK_PICK_UP_GOODS.getType().equals(robotCompleteTaskDTO.getCommandStatus().getCommandType()))) {
            releaseFromLocationAndSetRobotSkuInfo(robotCompleteTaskDTO);
        } else if (PathTaskTypeEnum.RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            releaseToLocation(robotCompleteTaskDTO);
            redisUtil.del(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + robotCompleteTaskDTO.getMac());
        } else {
            redisUtil.del(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + robotCompleteTaskDTO.getMac());
        }
        //todo 后面考虑下充电，车机目前对充电的逻辑未定义
        RobotTaskDetailDO robotTaskDetail = null;
        if (PathTaskTypeEnum.MOVE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.MOVE_TO_WAIT_STOP.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.MOVE_TO_POINT.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.TAKE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            robotTaskDetail = taskDone(robotCompleteTaskDTO);

        } else if (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
            if (CommandTypeEnum.WORK_PICK_UP_GOODS.getType().equals(robotCompleteTaskDTO.getCommandStatus().getCommandType())) {
                log.info("告诉路径规划取货任务完成 :{}, 状态: {}", robotCompleteTaskDTO.getOrderId(), PathIsReachEnum.END_WORK.getType());
                pathPlanningService.updateBehavior(String.valueOf(robotCompleteTaskDTO.getOrderId()), robotTaskDetailDO.getRobotNo()
                        , "", PathIsReachEnum.END_WORK.getType());
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_RELEASE.getType());
                robotTaskDetailMapper.updateById(robotTaskDetailDO);
                return;
            } else if (CommandTypeEnum.WORK_DROP_OFF_GOODS.getType().equals(robotCompleteTaskDTO.getCommandStatus().getCommandType())) {
                robotTaskDetail = taskDone(robotCompleteTaskDTO);
            }
        }

        if (PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            chargeLogMapper.updateChargStatusByTaskId(robotCompleteTaskDTO.getOrderId(), ChargeTaskStatusEnum.DONE.getType());
        }
        taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DONE.getType(), LocalDateTime.now());

        addTaskDetailActionDoneLog(robotCompleteTaskDTO, robotTaskDetail);

        TaskDistributionMessage mess = new TaskDistributionMessage(this, robotCompleteTaskDTO.getOrderId() + "",
                EventTypeEnum.TASK_DONE.getType());
        taskDistributionProducer.sendSmsSendMessage(mess);
    }

    private void addTaskDetailActionDoneLog(RobotCompleteTaskDTO robotCompleteTaskDTO, RobotTaskDetailDO robotTaskDetail) {
        RobotTaskDetailActionLogSaveReqVO logOne = new RobotTaskDetailActionLogSaveReqVO();
        String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
        logOne.setActionMsg("车辆 " + robotNo + " 完成任务");
        logOne.setRobotNo(robotNo);
        logOne.setOriginalRobotNo(robotNo);
        logOne.setTaskDetailId(robotCompleteTaskDTO.getOrderId());
        if (ObjectUtil.isNotEmpty(robotTaskDetail)) {
            logOne.setTaskStage(robotTaskDetail.getTaskStage());
            logOne.setCommandType(PathTaskTypeEnum.getTaskType(robotTaskDetail.getTaskType()));
        }
//        logOne.setTaskNo(robotTask.getTaskNo());
        logOne.setActionStatus(ActionStatusEnum.DONE.getType());
        logOne.setStartTime(LocalDateTime.now());
        logOne.setEndTime(LocalDateTime.now());
        Long mapId = robotInformationService.getRobotMapIdByRobotNo(robotNo);
        if (ObjectUtil.isNotEmpty(mapId)) {
            logOne.setPositionMapId(mapId);
        }
        taskDetailActionLogService.createTaskDetailActionLog(logOne);
    }

    /**
     * 释放放货库位
     *
     * @param robotCompleteTaskDTO
     */
    private void releaseToLocation(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
        if (ObjectUtil.isEmpty(robotTaskDetailDO) || ObjectUtil.isEmpty(robotTaskDetailDO.getToLocationId())) {
            return;
        }
        String actualLocationX = null;
        String actualLocationY = null;
        if (ReleaseTakeEnum.isLocation(robotTaskDetailDO.getReleaseType())) {
            WareHouseLocationDO toWareHouseLocation = locationMapper.selectById(robotTaskDetailDO.getToLocationId());
            if (ObjectUtil.isEmpty(toWareHouseLocation)) {
                return;
            }
            //查询最近一起取货任务
            WareHouseLocationDO fromWareHouseLocation = getFromLocation(robotTaskDetailDO);
            if (ObjectUtil.isNotEmpty(fromWareHouseLocation)) {
                toWareHouseLocation.setSkuNumber(fromWareHouseLocation.getSkuNumber());
                toWareHouseLocation.setSkuInfo(fromWareHouseLocation.getSkuInfo());
            }
            toWareHouseLocation.setLocationLock(LocationLockEnum.YES.getType());
            toWareHouseLocation.setLocationUseStatus(LocationUseStatusEnum.YES.getType());
            locationMapper.updateById(toWareHouseLocation);
            actualLocationX = toWareHouseLocation.getActualLocationX();
            actualLocationY = toWareHouseLocation.getActualLocationY();
        } else if (ReleaseTakeEnum.TO_POINT.getType().equals(robotTaskDetailDO.getReleaseType())) {
            WareHouseTakePointDO houseTakePoint = houseTakePointService.getHouseTakePoint(robotTaskDetailDO.getToLocationId());
            if (ObjectUtil.isEmpty(houseTakePoint)) {
                return;
            }
            actualLocationX = houseTakePoint.getActualLocationX();
            actualLocationY = houseTakePoint.getActualLocationY();
        }

        pushWareLocation(actualLocationX,actualLocationY, robotCompleteTaskDTO.getMac(), ZeroOneEnum.ONE.getType());
    }

    /**
     * 查询最近一次取货任务
     *
     * @param robotTaskDetailDO
     * @return
     */
    private WareHouseLocationDO getFromLocation(RobotTaskDetailDO robotTaskDetailDO) {
        if (RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(robotTaskDetailDO.getTaskType())
                && ObjectUtil.isNotEmpty(robotTaskDetailDO.getFromLocationId())) {
            return locationMapper.selectById(robotTaskDetailDO.getFromLocationId());
        }
        List<RobotTaskDetailActionLogDO> actionLogs = taskDetailActionLogMapper.getLastTwoTask(robotTaskDetailDO.getRobotNo());
        if (ObjectUtil.isEmpty(actionLogs)) {
            return null;
        }
        for (RobotTaskDetailActionLogDO actionLog : actionLogs) {
            if (!robotTaskDetailDO.getId().equals(actionLog.getTaskDetailId())) {
                RobotTaskDetailDO taskDetail = robotTaskDetailMapper.selectById(actionLog.getTaskDetailId());
                if (ObjectUtil.isEmpty(taskDetail) || !RobotTaskTypeEnum.TAKE.getType().equals(taskDetail.getTaskType())
                        || ObjectUtil.isEmpty(taskDetail.getFromLocationId())) {
                    continue;
                }
                locationMapper.selectById(taskDetail.getFromLocationId());
            }
        }
        return null;
    }

    /**
     * 设置车辆上的物料信息，释放取货库位
     *
     * @param robotCompleteTaskDTO
     */
    private void releaseFromLocationAndSetRobotSkuInfo(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
        if (ObjectUtil.isEmpty(robotTaskDetailDO) || ObjectUtil.isEmpty(robotTaskDetailDO.getFromLocationId())) {
            return;
        }

        Long skuNumber = null;
        String skuInfo = null;
        Integer locationStorey = null;

        if (ReleaseTakeEnum.isLocation(robotTaskDetailDO.getTakeType())) {
            WareHouseLocationDO wareHouseLocationDO = locationMapper.selectById(robotTaskDetailDO.getFromLocationId());
            if (ObjectUtil.isEmpty(wareHouseLocationDO)) {
                return;
            }
            skuNumber = wareHouseLocationDO.getSkuNumber();
            skuInfo = wareHouseLocationDO.getSkuInfo();
            locationStorey = wareHouseLocationDO.getLocationStorey();

            wareHouseLocationDO.setSkuInfo(null);
            wareHouseLocationDO.setSkuNumber(0L);
            wareHouseLocationDO.setLocationLock(LocationLockEnum.YES.getType());
            wareHouseLocationDO.setLocationUseStatus(LocationUseStatusEnum.NO.getType());
            locationMapper.updateById(wareHouseLocationDO);
            pushWareLocation(wareHouseLocationDO.getActualLocationX(),wareHouseLocationDO.getActualLocationY(), robotCompleteTaskDTO.getMac(), ZeroOneEnum.ZERO.getType());
        } else if (ReleaseTakeEnum.TO_POINT.getType().equals(robotTaskDetailDO.getTakeType())) {
            WareHouseTakePointDO houseTakePoint = houseTakePointService.getHouseTakePoint(robotTaskDetailDO.getFromLocationId());
            if (ObjectUtil.isEmpty(houseTakePoint)) {
                return;
            }
            houseTakePoint.setSkuInfo(null);
            houseTakePoint.setSkuNumber(0L);
            houseTakePoint.setPointStatus(ZeroOneEnum.ZERO.getType());
            houseTakePointService.updateById(houseTakePoint);
            pushWareLocation(houseTakePoint.getActualLocationX(),houseTakePoint.getActualLocationY(), robotCompleteTaskDTO.getMac(), ZeroOneEnum.ZERO.getType());
        }

        RobotSkuInfoDTO robotSkuInfo = new RobotSkuInfoDTO();
        robotSkuInfo.setHaveSku(ZeroOneEnum.ONE.getType());
        robotSkuInfo.setSkuNumber(skuNumber);
        robotSkuInfo.setSkuInfo(skuInfo);
        robotSkuInfo.setLocationStorey(locationStorey);
        redisUtil.set(RobotTaskChcheConstant.ROBOT_TASK_SKU_INFO + robotCompleteTaskDTO.getMac(), JSON.toJSONString(robotSkuInfo));
    }

    public void pushWareLocation(String actualLocationX,String actualLocationY, String mac, Integer type) {
        String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + mac;
        Object floorAreaObject = redisUtil.get(floorAreaKey);
        if (ObjectUtil.isEmpty(floorAreaObject)) {
            return;
        }
        FloorZoneDTO floorZoneDTO = JSONUtil.toBean((String) floorAreaObject, FloorZoneDTO.class);
        String floorAreaStr = floorZoneDTO.getFloor() + CommonConstant.SYMBOL + floorZoneDTO.getArea();
        WsWareHouseLocationDTO wsWareHouseLocation = new WsWareHouseLocationDTO();
        wsWareHouseLocation.setActualLocationX(actualLocationX);
        wsWareHouseLocation.setActualLocationY(actualLocationY);
        wsWareHouseLocation.setType(type);
        wsWareHouseLocation.setFloor(floorZoneDTO.getFloor());
        wsWareHouseLocation.setArea(floorZoneDTO.getArea());
        log.info("让3D推送修改库存 :{}", JSON.toJSONString(wsWareHouseLocation));
        webSocketSenderApi.sendObject(floorAreaStr, WebSocketConstant.THREE_D_CHANGE_STOCK, JSON.toJSONString(wsWareHouseLocation));
    }


    /**
     * 通知PP关闭任务
     *
     * @param robotCompleteTaskDTO
     */
    public void PPCloseOrder(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
        RobotClosePathPlantingDTO closePathPlanting = RobotClosePathPlantingDTO.builder()
                .robotNo(robotNo)
                .id(robotCompleteTaskDTO.getOrderId().toString())
                .build();
//        commonApi.commonMethod(closePathPlanting, PathPlanningTopicConstant.KILL_TASK);
        mqttUtils.pub(PathPlanningTopicConstant.KILL_TASK, JSON.toJSONString(closePathPlanting));
        log.info("通知PP把任务取消 :{}", robotCompleteTaskDTO.getOrderId());
    }

    /**
     * 处理机器人上报的异常
     *
     * @param robotCompleteTaskDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void closeTask(RobotCompleteTaskDTO robotCompleteTaskDTO) {

        if (RobotStatusCodeEnum.EXCEEDING_SECONDS.getType().equals(robotCompleteTaskDTO.getStatusCode())) {
            doTaskContinue(robotCompleteTaskDTO);
            return;
        }

        PPCloseOrder(robotCompleteTaskDTO);
//        taskService.closeTaskDetail(robotCompleteTaskDTO.getOrderId().toString(),robotCompleteTaskDTO.getMac());
        String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
        String taskNo = taskDetailService.getTaskNoByDetailId(robotCompleteTaskDTO.getOrderId());
        String msg = null;
        RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
        if (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.TAKE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            RobotTaskDetailDO detailDO = new RobotTaskDetailDO();
            if (RobotTaskStageEnum.GO_TAKE.getType().equals(robotTaskDetailDO.getTaskStage())
                    || RobotTaskStageEnum.UN_START.getType().equals(robotTaskDetailDO.getTaskStage())) {
                detailDO.setTaskStatus(RobotTaskDetailStatusEnum.NEW.getType());
                detailDO.setTaskStage(RobotTaskStageEnum.UN_START.getType());

                if (!znConfigConstant.getIsSimulation()) {
//                    robotTaskDetailDO.setRobotNo("");
                }
                detailDO.setOccurError(ZeroOneEnum.ZERO.getType());
//                robotTaskDetailMapper.updateById(robotTaskDetailDO);
                robotTaskDetailMapper.updateRobotDetailById(detailDO);
                msg = robotNo + "_" + "车辆发生异常,重新分配其他车辆执行此任务" + taskNo + " - " + robotTaskDetailDO.getFromLocationNo();
            }
        }


        //先不释放库位状态
        /*if (RobotTaksOrderTypeEnum.TASK.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            RobotTaskDetailDO robotTaskDetailDO = closeTaskDetail(robotCompleteTaskDTO.getOrderId());
            List<Long> locationIds = new ArrayList<>();
            if (ObjectUtil.isNotEmpty(robotTaskDetailDO.getFromLocationId())) {
                locationIds.add(robotTaskDetailDO.getFromLocationId());
            }
            if (ObjectUtil.isNotEmpty(robotTaskDetailDO.getToLocationId())) {
                locationIds.add(robotTaskDetailDO.getToLocationId());
            }
            if (ObjectUtil.isNotEmpty(locationIds)) {
                locationMapper.releaseLocationLockList(locationIds, robotTaskDetailDO.getRobotTaskId()
                        , LocationLockEnum.YES.getType());
            }

        } else if (RobotTaksOrderTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {

            RobotChargeLogDO robotChargeLogDO = chargeLogMapper.selectOne(new LambdaQueryWrapper<RobotChargeLogDO>()
                    .eq(RobotChargeLogDO::getId, robotCompleteTaskDTO.getOrderId()));
            robotChargeLogDO.setTaskStatus(ChargeTaskStatusEnum.ABNORMAL.getType());
            chargeLogMapper.updateById(robotChargeLogDO);

            if (ObjectUtil.isNotEmpty(robotChargeLogDO.getTaskDetailId())) {
                closeTaskDetail(robotCompleteTaskDTO.getOrderId());
            }
            deviceInformationMapper.updateDeviceUseStatus(robotChargeLogDO.getDeviceNo(),
                    DeviceUseStatusEnum.IDLE.getType(), ZeroOneEnum.ZERO.getType());
        }*/

        String solve = "";
        if (ObjectUtil.isEmpty(msg)) {
            solve = " 并且到任务列表关闭任务 " + taskNo;
            taskDetailService.setTaskDetailError(robotCompleteTaskDTO.getOrderId());
        } else {
            robotInformationService.lockRobot(robotNo);
        }

        msg = ObjectUtil.isEmpty(msg) ? taskNo +" 车辆编号_"+ robotNo + "_" + robotCompleteTaskDTO.getMessage() : msg;

        RobotWarnMsgDO warnMsg = RobotWarnMsgDO.builder().warnLevel(4)
                .warnCode(robotCompleteTaskDTO.getStatusCode())
                .robotNo(robotNo)
                .warnType(RobotWarnType.ROBOT_WARN.getType())
                .warnMsg(msg)
                .taskNo(taskNo)
                .taskDetailId(robotCompleteTaskDTO.getOrderId())
                .warnSolve(robotCompleteTaskDTO.getSolution() + solve)
                .build();
        warnMsgMapper.insert(warnMsg);

        warnMsgService.sendWarnMsgToWebsocket(warnMsg.getWarnMsg());
    }

    private void doTaskContinue(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        log.info("恢复任务");
        String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
        robotInformationService.doTaskContinue(robotNo, true);
    }

    /**
     * 处理充电中
     *
     * @param robotCompleteTaskDTO
     */
    private void chargeDoing(RobotCompleteTaskDTO robotCompleteTaskDTO) {

        RobotCommandStateDTO commandStatus = robotCompleteTaskDTO.getCommandStatus();

        //自动充电任务，移动到充电点就改为完成
        if (ObjectUtil.isNotEmpty(commandStatus) && CommandTypeEnum.MOVE_POSES.getType().equals(commandStatus.getCommandType())
                && RobotExecutionStateConstant.DONE.equals(commandStatus.getExecutionState())) {
            taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DONE.getType(), LocalDateTime.now());
            setTaskDone(robotCompleteTaskDTO);
        }

        chargeLogMapper.updateChargStatusByTaskId(robotCompleteTaskDTO.getOrderId(), ChargeTaskStatusEnum.CHARGEING.getType());
    }

    public RobotTaskDetailDO setTaskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        //更新任务状态
        RobotTaskDetailDO detailDO = new RobotTaskDetailDO();
        detailDO.setId(robotCompleteTaskDTO.getOrderId());
        detailDO.setEndTime(LocalDateTime.now());
        detailDO.setTaskStage(RobotTaskStageEnum.DONE.getType());
        detailDO.setTaskStatus(RobotTaskDetailStatusEnum.DONE.getType());
        robotTaskDetailMapper.updateRobotDetailById(detailDO);
        //更新任务状态
        RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
        List<RobotTaskDetailDO> taskDetails = robotTaskDetailMapper.queryByTaskId(robotTaskDetailDO.getRobotTaskId());
        boolean done =
                taskDetails.stream().noneMatch(v -> (v.getTaskStatus().equals(RobotTaskDetailStatusEnum.NEW.getType())
                        || v.getTaskStatus().equals(RobotTaskDetailStatusEnum.DOING.getType())));
        if (done) {
            RobotTaskDO robotTaskDO = new RobotTaskDO();
            robotTaskDO.setId(taskDetails.get(0).getRobotTaskId());
            robotTaskDO.setEndTime(LocalDateTime.now());
            robotTaskDO.setTaskStatus(RobotTaskDetailStatusEnum.DONE.getType());
            robotTaskMapper.updateRobot(robotTaskDO);
//            taskCycleMapper.deletByRobotTaskId(taskDetails.get(0).getRobotTaskId());
        }
        return robotTaskDetailDO;
    }

    /**
     * 任务完成
     *
     * @param robotCompleteTaskDTO
     */
    private RobotTaskDetailDO taskDone(RobotCompleteTaskDTO robotCompleteTaskDTO) {

        RobotTaskDetailDO robotTaskDetailDO = setTaskDone(robotCompleteTaskDTO);

        RobotInformationDO robotInformationDO = robotInformationMapper.selectOne(new LambdaQueryWrapperX<RobotInformationDO>()
                .eq(RobotInformationDO::getRobotNo, robotTaskDetailDO.getRobotNo()));
        robotInformationDO.setRobotStatus(RobotStatusEnum.STAND_BY.getType());
        if (RobotTaskTypeEnum.MOVE.getType().equals(robotTaskDetailDO.getTaskType())
                || (RobotTaskTypeEnum.PARK.getType().equals(robotTaskDetailDO.getTaskType())
                && ZeroOneEnum.ONE.getType().equals(robotTaskDetailDO.getNeedLock()))) {
            robotInformationDO.setRobotTaskModel(RobotTaskModelEnum.REJECTION.getType());
        }
        robotInformationMapper.updateById(robotInformationDO);

        //同步任务完成给PP
        pathPlanningService.updateBehavior(String.valueOf(robotCompleteTaskDTO.getOrderId()), robotTaskDetailDO.getRobotNo()
                , "", PathIsReachEnum.END_WORK.getType());

        if (!znConfigConstant.getIsSimulation()) {
            String plantingKey = PathPlanningChcheConstant.PATH_PLANNING_TASK + robotCompleteTaskDTO.getOrderId();
            redisUtil.del(plantingKey);
        }
        return robotTaskDetailDO;
    }


    /**
     * 任务处理中
     *
     * @param robotCompleteTaskDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void taskDoing(RobotCompleteTaskDTO robotCompleteTaskDTO, String robotDoingActionKey) {

        RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(robotCompleteTaskDTO.getOrderId());
        Long taskStage = robotTaskDetailDO.getTaskStage();
        log.info("任务 :{} , 当前阶段 :{}", robotCompleteTaskDTO.getOrderId(), taskStage);

        RobotTaskDO robotTask = robotTaskMapper.selectById(robotTaskDetailDO.getRobotTaskId());

        RobotCommandStateDTO commandStatus = robotCompleteTaskDTO.getCommandStatus();
        String commandType = commandStatus.getCommandType();

        RobotTaskDetailActionLogSaveReqVO logOne = new RobotTaskDetailActionLogSaveReqVO();
        if (PathTaskTypeEnum.TAKE_RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            if (CommandTypeEnum.WORK_PICK_UP_GOODS_MOVE_TO_CHECK.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getFromLocationNo() + "取货");
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_TAKE.getType());
            } else if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType) && (RobotTaskStageEnum.UN_START.getType().equals(taskStage)
                    || RobotTaskStageEnum.GO_TAKE.getType().equals(taskStage)
                    || RobotTaskStageEnum.TAKEING.getType().equals(taskStage))) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getFromLocationNo() + "取货");
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_TAKE.getType());
            } else if (CommandTypeEnum.WORK_PICK_UP_GOODS.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在取货" + robotTaskDetailDO.getFromLocationNo());
                if (!RobotTaskStageEnum.GO_RELEASE.getType().equals(taskStage)) {
                    robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.TAKEING.getType());
                }
            } else if (CommandTypeEnum.WORK_DROP_OFF_GOODS.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在放货" + robotTaskDetailDO.getToLocationNo());
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.RELEASEING.getType());
            } else if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType)
                    || CommandTypeEnum.WORK_DROP_OFF_GOODS_MOVE_TO_CHECK.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getToLocationNo() + "放货");
                if (!RobotTaskStageEnum.DONE.getType().equals(taskStage)) {
                    robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_RELEASE.getType());
                }
            }

        } else if (PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            RobotChargeLogDO robotChargeLogDO = chargeLogMapper.selectById(robotCompleteTaskDTO.getOrderId());
            if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在前往 " + robotChargeLogDO.getDeviceNo() + "充电");
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.MOVE.getType());
            } else {
                logOne.setActionMsg("车辆正在充电 " + robotChargeLogDO.getDeviceNo());
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.CHARGEING.getType());
            }

        } else if (PathTaskTypeEnum.MOVE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.MOVE_TO_WAIT.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.MOVE_TO_POINT.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getToLocationNo());
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.MOVE.getType());
            }
        } else if (PathTaskTypeEnum.MOVE_TO_WAIT_STOP.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getToLocationNo());
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.MOVE.getType());
            }
        } else if (PathTaskTypeEnum.TAKE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType) && RobotTaskStageEnum.UN_START.getType().equals(taskStage)) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getFromLocationNo() + "取货");
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_TAKE.getType());
            } else if (CommandTypeEnum.WORK_PICK_UP_GOODS.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在取货" + robotTaskDetailDO.getFromLocationNo());
                if (!RobotTaskStageEnum.DONE.getType().equals(taskStage)) {
                    robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.TAKEING.getType());
                }
            }

        } else if (PathTaskTypeEnum.RELEASE.getType().equals(robotCompleteTaskDTO.getOrderType())) {
            if (CommandTypeEnum.MOVE_POSES.getType().equals(commandType) && RobotTaskStageEnum.UN_START.getType().equals(taskStage)) {
                logOne.setActionMsg("车辆正在前往" + robotTaskDetailDO.getToLocationNo() + "放货");
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_RELEASE.getType());
            } else if (CommandTypeEnum.WORK_DROP_OFF_GOODS.getType().equals(commandType)) {
                logOne.setActionMsg("车辆正在放货" + robotTaskDetailDO.getToLocationNo());
                if (!RobotTaskStageEnum.DONE.getType().equals(taskStage)) {
                    robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.RELEASEING.getType());
                }
            }
        }

        //编辑地图会判断这表的状态,所以自动充电任务，移动到充电点就改为完成
        if (ObjectUtil.isNotEmpty(commandStatus) && CommandTypeEnum.MOVE_POSES.getType().equals(commandStatus.getCommandType())
                && RobotExecutionStateConstant.DONE.equals(commandStatus.getExecutionState())
                && (PathTaskTypeEnum.CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType())
                || PathTaskTypeEnum.AUTO_CHARGE.getType().equals(robotCompleteTaskDTO.getOrderType()))) {
            taskDetailActionLogMapper.updateActionStatus(robotCompleteTaskDTO.getOrderId(), ActionStatusEnum.DONE.getType(), LocalDateTime.now());
        }

        String robotNo = robotInformationService.getRobotNoByMac(robotCompleteTaskDTO.getMac());
        logOne.setRobotNo(robotNo);
        logOne.setOriginalRobotNo(robotNo);
        logOne.setTaskDetailId(robotCompleteTaskDTO.getOrderId());
        logOne.setTaskStage(robotTaskDetailDO.getTaskStage());
        logOne.setCommandType(PathTaskTypeEnum.getTaskType(robotTaskDetailDO.getTaskType()));
        logOne.setTaskNo(robotTask.getTaskNo());
        logOne.setActionStatus(ActionStatusEnum.DOING.getType());
        logOne.setStartTime(LocalDateTime.now());
        Long mapId = robotInformationService.getRobotMapIdByRobotNo(robotNo);
        if (ObjectUtil.isNotEmpty(mapId)) {
            logOne.setPositionMapId(mapId);
        }
        taskDetailActionLogService.createTaskDetailActionLog(logOne);
        redisUtil.set(robotDoingActionKey, logOne.getActionMsg(), znConfigConstant.getRobotDoingAction().getDoingActionCacheTime());
        robotTaskDetailMapper.updateById(robotTaskDetailDO);
    }

    public void freeLocation(Boolean isTake, Long taskDetailId) {
        RobotTaskDetailDO robotTaskDetailDO = robotTaskDetailMapper.selectById(taskDetailId);
        if (ObjectUtil.isNotEmpty(robotTaskDetailDO) && ObjectUtil.isNotEmpty(robotTaskDetailDO.getFromLocationId())
                && isTake) {
            WareHouseLocationDO wareHouseLocationDO = new WareHouseLocationDO();
            wareHouseLocationDO.setId(robotTaskDetailDO.getFromLocationId());
            wareHouseLocationDO.setLocationLock(LocationLockEnum.YES.getType());
            wareHouseLocationDO.setSkuBatch("");
            wareHouseLocationDO.setSkuInfo("");
            wareHouseLocationDO.setSkuNumber(0l);
            wareHouseLocationDO.setLocationUseStatus(LocationUseStatusEnum.NO.getType());
            locationMapper.updateEntity(wareHouseLocationDO);
        }

        if (ObjectUtil.isNotEmpty(robotTaskDetailDO) && ObjectUtil.isNotEmpty(robotTaskDetailDO.getToLocationId())
                && !isTake) {
            RobotTaskDO robotTask = robotTaskMapper.selectById(robotTaskDetailDO.getRobotTaskId());
            WareHouseLocationDO wareHouseLocationDO = new WareHouseLocationDO();
            wareHouseLocationDO.setId(robotTaskDetailDO.getFromLocationId());
            wareHouseLocationDO.setLocationLock(LocationLockEnum.YES.getType());
            wareHouseLocationDO.setSkuBatch(robotTask.getSkuBatch());
            wareHouseLocationDO.setSkuInfo(robotTask.getSkuInfo());
            wareHouseLocationDO.setSkuNumber(robotTask.getSkuNumber());
            wareHouseLocationDO.setLocationUseStatus(LocationUseStatusEnum.YES.getType());
            locationMapper.updateEntity(wareHouseLocationDO);
        }
    }

    /**
     * 机器人完成任务上报
     *
     * @param robotCompleteTaskDTO
     * @return
     */
    @Override
    public void robotDoneTask(RobotCompleteTaskDTO robotCompleteTaskDTO) {
        taskExecutor.execute(() -> {
            String requestId = UUID.randomUUID().toString().replace("-", "");
            MDC.put(CommonConstant.REQUEST_ID, requestId);
            try {
                doRobotDoneTask(robotCompleteTaskDTO);
            } finally {
                MDC.clear();
            }
        });
    }
}
