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

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.mqtt.api.task.dto.RobotAcceptTaskDTO;
import cn.iocoder.yudao.module.mqtt.api.task.dto.RobotSimulationPoseDTO;
import cn.iocoder.yudao.module.system.api.path.PathApi;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteRobotDTO;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteRobotDetailDTO;
import cn.iocoder.yudao.module.system.constant.area.FloorAreaConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.PositionMapDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.detail.RobotDoingTaskDTO;
import cn.iocoder.yudao.module.system.controller.admin.robot.mapstop.RobotMapStopSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnMsgSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapDO;
import cn.iocoder.yudao.module.system.dal.dataobject.remote.RemoteControllerInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotMapStopDO;
import cn.iocoder.yudao.module.system.dal.mysql.information.DeviceInformationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapMapper;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.remote.RemoteModeEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotCommandTypeEnum;
import cn.iocoder.yudao.module.system.service.housearea.HouseAreaService;
import cn.iocoder.yudao.module.system.service.houselane.WareHouseLaneService;
import cn.iocoder.yudao.module.system.service.houselocation.HouseLocationService;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.parkingspot.ParkingSpotService;
import cn.iocoder.yudao.module.system.service.remote.RemoteControllerInformationService;
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.service.robot.mapstop.RobotMapStopService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
import org.yaml.snakeyaml.Yaml;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

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

/**
 * 仓库点位地图 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class PositionMapServiceImpl extends ServiceImpl<PositionMapMapper, PositionMapDO> implements PositionMapService {

    @Resource
    private PositionMapMapper positionMapMapper;
    @Value("${map.file.upload-path}")
    private String UPLOAD_DIR;

    @Resource
    private RobotInformationService informationService;

    @Resource
    @Lazy
    private PathApi pathApi;

    @Resource
    private UserOperationLogService userOperationLogService;

    @Resource
    private RobotMapStopService robotMapStopService;

    @Resource
    @Lazy
    private RobotTaskDetailService taskDetailService;

    @Resource
    private RemoteControllerInformationService controllerInformationService;

    @Resource
    private PositionMapItemService positionMapItemService;

    @Resource
    private PositionMapLineService positionMapLineService;

    @Resource
    private HouseLocationService houseLocationService;

    @Resource
    private DeviceInformationMapper deviceInformationMapper;

    @Resource
    private PositionChangePointBindingService positionChangePointBindingService;

    @Resource
    private HouseAreaService houseAreaService;

    @Resource
    private WareHouseLaneService houseLaneService;

    @Resource
    private RobotWarnMsgService warnMsgService;

    @Resource
    private ParkingSpotService parkingSpotService;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public Long createPositionMap(PositionMapSaveReqVO createReqVO) {
        // 插入
        PositionMapDO positionMap = BeanUtils.toBean(createReqVO, PositionMapDO.class);
        positionMapMapper.insert(positionMap);
        // 返回
        return positionMap.getId();
    }

    @Override
    public void updatePositionMap(PositionMapSaveReqVO updateReqVO) {
        // 更新
        PositionMapDO updateObj = BeanUtils.toBean(updateReqVO, PositionMapDO.class);
        positionMapMapper.updateById(updateObj);
    }

    @Override
    public void deletePositionMap(Long id) {
        // 删除
        positionMapMapper.deleteById(id);
    }


    @Override
    public PositionMapDO getPositionMap(Long id) {
        return positionMapMapper.selectById(id);
    }

    @Override
    public PageResult<PositionMapDO> getPositionMapPage(PositionMapPageReqVO pageReqVO) {
        return positionMapMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadFiles(MultipartFile[] files) {
        if (files == null || files.length < 2) {
            throw exception(PLEASE_UPLOAD_PNG_AND_YAML_FILES);
        }
        MultipartFile yamlFile = null;
        MultipartFile pngFile = null;
        // 分类文件
        for (MultipartFile file : files) {
            if (Objects.requireNonNull(file.getOriginalFilename()).toLowerCase().endsWith(".yaml")) {
                yamlFile = file;
            } else if (Objects.requireNonNull(file.getOriginalFilename()).toLowerCase().endsWith(".png")) {
                pngFile = file;
            }
        }
        if (yamlFile == null || pngFile == null || yamlFile.isEmpty() || pngFile.isEmpty()) {
            throw exception(PLEASE_UPLOAD_PNG_AND_YAML_FILES);
        }
        // 处理 YAML 文件 - 返回yaml中存储的楼层信息 作为png文件存储的目录
        String url = null;
        String yamlJson = null;
        String yamlUrl = null;
        String pngUrl = null;
        Integer floorInt = null;
        String areaStr = null;
        try {
            // Get the file and save it somewhere
            byte[] bytes = yamlFile.getBytes();
            // Parse the YAML file
            Yaml yaml = new Yaml();
            Map<String, Object> data = yaml.load(new String(bytes, StandardCharsets.UTF_8));
            Object floor = data.get("floor");
            Object area = data.get("area");

            // -- 根据楼和区域查询是否有存在地图信息 - 如果有存在则替换 - 并且通知所有该楼该区域的AGV
            if (ObjUtil.isEmpty(floor) || ObjUtil.isEmpty(area)) {
                throw exception(AGV_UPLOAD_INFORMATION_DOES_NOT_INCLUDE_FLOOR_OR_AREA_INFORMATION);
            }
            floorInt = Integer.parseInt(Objects.requireNonNull(floor).toString());
            areaStr = Objects.requireNonNull(area).toString();
            url = UPLOAD_DIR + floor + "/" + area + "/";
            // 判断目录是否存在 - 如果不存在则创建目录
            File directory = new File(url);
            if (!directory.exists()) {
                directory.mkdirs();
            }
            yamlUrl = url + yamlFile.getOriginalFilename();
            Path path = Paths.get(yamlUrl);
            Files.write(path, bytes);
            // Convert the YAML data to JSON
            ObjectMapper objectMapper = new ObjectMapper();
            yamlJson = objectMapper.writeValueAsString(data);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("Failed to upload '{}'", e);
            return;
        }

        PositionMapDO positionMap = positionMapMapper.selectOne(new LambdaQueryWrapperX<PositionMapDO>()
                .eq(PositionMapDO::getFloor, floorInt)
                .eq(PositionMapDO::getArea, areaStr));
        if (ObjectUtil.isNotEmpty(positionMap)) {
            positionMapMapper.deleteById(positionMap.getId());
            List<WareHouseLocationDO> locationDOList = houseLocationService.getInStockLockLocationByMapId(positionMap.getId());
            if (ObjectUtil.isNotEmpty(locationDOList)) {
                warnMsgService.sendWarnMsgToWebsocket(MAP_EXIST_TASK_EXIST_TASK.getMsg());
                RobotWarnMsgSaveReqVO warnMsgSaveReqVO = new RobotWarnMsgSaveReqVO();
                List<String> locationNos = locationDOList.stream().map(WareHouseLocationDO::getLocationNo).collect(Collectors.toList());
                String locationStr = StringUtils.join(locationNos, ",");
                if (locationStr.length() > 160) {
                    locationStr = locationStr.substring(0,160);
                }
                warnMsgSaveReqVO.setWarnMsg(MAP_EXIST_TASK_EXIST_TASK.getMsg()+locationStr);
                warnMsgSaveReqVO.setWarnLevel(4);
                warnMsgSaveReqVO.setWarnCode("MAP");
                warnMsgSaveReqVO.setSolveTime(LocalDateTime.now());
                warnMsgService.createWarnMsg(warnMsgSaveReqVO);
                throw exception(MAP_EXIST_TASK_EXIST_TASK);
            }
            positionMapItemService.checkHaveBindChangePoint(positionMap.getId());
            positionMapItemService.deleteByMapId(positionMap.getId());
            positionMapLineService.deleteByMapId(positionMap.getId());
            houseLocationService.deleteHouseLocationByMapId(positionMap.getId());
            deviceInformationMapper.deleteDeviceByMapId(positionMap.getId());
            positionChangePointBindingService.deleteBindingByMapId(positionMap.getId());
            houseAreaService.deleteHouseAreaByMapId(positionMap.getId());
            houseLaneService.deleteHouseLaneByMapId(positionMap.getId());
            parkingSpotService.deleteParkingByMapId(positionMap.getId());
            redisUtil.del("pngBase64");
            redisUtil.del(FloorAreaConstant.FLOOR_AREA_ALL);
            pathApi.pathInitData();
        }

        // 处理 PNG 文件
        try {
            pngUrl = url + pngFile.getOriginalFilename();
            byte[] bytes = pngFile.getBytes();
            Path path = Paths.get(pngUrl);
            Files.write(path, bytes);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        // todo 异步通知所有该楼层区域内所有AGV车地图有更改 - 这个时候AGV应当重新获取地图信息
        positionMap = new PositionMapDO().setFloor(floorInt).setArea(areaStr)
                .setYamlJson(yamlJson).setPngUrl(pngUrl).setYamlUrl(yamlUrl);
        positionMapMapper.insert(positionMap);
    }

    @Override
    public void downloadFile(Integer floor, String area, HttpServletResponse response) throws IOException {
        PositionMapDO positionMapDO = positionMapMapper.selectOne(new LambdaQueryWrapperX<PositionMapDO>()
                .eq(PositionMapDO::getFloor, floor)
                .eq(PositionMapDO::getArea, area));
        if (positionMapDO == null) {
            throw exception(AGV_MAP_NOT_FOUND);
        }

        // 假设文件存储路径，根据实际情况修改
        String basePath = UPLOAD_DIR + floor + "/" + area + "/";
        List<File> filesToZip = findFilesByFloorAndArea(basePath);

        if (filesToZip.isEmpty()) {
            response.sendError(HttpStatus.NOT_FOUND.value(), "No files found for the given floor and area.");
            return;
        }

        response.setContentType("application/zip");
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"files.zip\"");

        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
            for (File file : filesToZip) {
                ZipEntry zipEntry = new ZipEntry(file.getName());
                zipOut.putNextEntry(zipEntry);
                try (FileInputStream fileIn = new FileInputStream(file)) {
                    IOUtils.copy(fileIn, zipOut);
                }
                zipOut.closeEntry();
            }
        }
    }

    private List<File> findFilesByFloorAndArea(String basePath) {
        List<File> foundFiles = new ArrayList<>();
        File directory = new File(basePath);
        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                foundFiles.addAll(Arrays.asList(files));
            }
        }
        return foundFiles;
    }


    @Override
    public void downloadFile(HttpServletResponse response) throws IOException {
        // 指定要压缩的文件夹路径
        Path folderPath = Paths.get(UPLOAD_DIR);

        if (!Files.exists(folderPath) || !Files.isDirectory(folderPath)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Folder not found");
            return;
        }

        // 设置响应头
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=project.zip");

        // 压缩文件夹并写入响应体
        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
            addFolderToZip(folderPath.toFile(), folderPath.toString(), zipOut);
        }
    }


    private void addFolderToZip(File folder, String baseFolder, ZipOutputStream zipOut) throws IOException {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    addFolderToZip(file, baseFolder, zipOut);
                    continue;
                }
                FileInputStream fis = new FileInputStream(file);
                ZipEntry zipEntry = new ZipEntry(file.getAbsolutePath().substring(baseFolder.length() + 1));
                zipOut.putNextEntry(zipEntry);

                byte[] bytes = new byte[1024];
                int length;
                while ((length = fis.read(bytes)) >= 0) {
                    zipOut.write(bytes, 0, length);
                }
                fis.close();
            }
        }
    }


    @Override
    @Cacheable(value = "pngBase64", key = "#floor + '_' + #area")
    public String downloadPngBase64(Integer floor, String area) {
        // 根据楼层和区域查找对应的PNG文件路径
        String basePath = UPLOAD_DIR + floor + "/" + area + "/";
        File directory = new File(basePath);
        if (!directory.exists() || !directory.isDirectory()) {
            log.error("Directory not found for floor: {}, area: {}", floor, area);
            throw exception(AGV_MAP_NOT_FOUND);
        }

        // 查找PNG文件
        File pngFile = null;
        File[] files = directory.listFiles((dir, name) -> name.toLowerCase().endsWith(".png"));
        if (files != null && files.length > 0) {
            pngFile = files[0]; // 假设每个目录下只有一个PNG文件
        }

        if (pngFile == null || !pngFile.exists()) {
            log.error("PNG file not found for floor: {}, area: {}", floor, area);
            throw exception(AGV_MAP_NOT_FOUND);
        }
        String encodedString = null;
        try {
            // 读取文件内容
            byte[] fileContent = Files.readAllBytes(pngFile.toPath());
            // 将文件内容转换为Base64字符串
            encodedString = Base64.getEncoder().encodeToString(fileContent);
            // 添加MIME类型前缀
            encodedString = "data:image/png;base64," + encodedString;
        } catch (IOException e) {
            log.error("Failed to convert PNG to Base64 for floor: {}, area: {}", floor, area, e);
            throw exception(AGV_IMAGE_CONVERSION_TO_BASE64_FAILED);
        }
        return encodedString;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void emergencyStopOrRecovery(Long id, Integer type, Boolean isRemote) {
        // 先获取当前地图上的所有AGV信息
        PositionMapDO positionMapDO = positionMapMapper.selectById(id);

        RobotAcceptTaskDTO robotSimulationPose = new RobotAcceptTaskDTO();

        List<String> robotNos = new ArrayList<>();
        String str = "";
        String mapStr = positionMapDO.getFloor() + "层 " + positionMapDO.getArea() + " 所有车辆";
        //暂停
        if (ZeroOneEnum.ONE.getType().equals(type)) {
            robotNos = informationService.getRobotByFloorAndArea(String.valueOf(positionMapDO.getFloor()), positionMapDO.getArea());
            robotSimulationPose.setExecutionType(RobotCommandTypeEnum.PAUSE.getType());
            str = RobotCommandTypeEnum.PAUSE.getMsg();
            if (isRemote) {
                mapStr = "远遥一键暂停 " + mapStr;
            } else {
                mapStr = "一键暂停 " + mapStr;
            }

            //过滤已经暂停的
            if (ObjectUtil.isNotEmpty(robotNos)) {
                List<RobotMapStopDO> robotMapStopList = robotMapStopService.getStopRobotNoByRobotNoList(robotNos);
                if (ObjectUtil.isNotEmpty(robotMapStopList)) {
                    List<String> stopRobotNos = robotMapStopList.stream().map(RobotMapStopDO::getRobotNo).collect(Collectors.toList());
                    robotNos.removeAll(stopRobotNos);
                }
            }

        } else {
            //恢复
            robotNos = robotMapStopService.getStopRobotNoByMapIds(id);
            robotSimulationPose.setExecutionType(RobotCommandTypeEnum.CONTINUE.getType());
            str = RobotCommandTypeEnum.CONTINUE.getMsg();
            if (isRemote) {
                mapStr = "远遥一键恢复 " + mapStr;
            } else {
                mapStr = "一键恢复 " + mapStr;
            }
            robotMapStopService.deleteRobotMapStopByMapId(id);
            if (ObjectUtil.isNotEmpty(robotNos)) {
                robotMapStopService.deleteRobotMapStopByRobotNos(robotNos);
            }
        }

        if (ObjectUtil.isEmpty(robotNos)) {
            throw exception(MAP_DOES_NOT_EXIST_AGV);
        }

        if (ZeroOneEnum.ONE.getType().equals(type)) {
            robotMapStopService.createRobotMapStop(id, robotNos);
            RobotMapStopSaveReqVO robotMapStopSave = new RobotMapStopSaveReqVO();
            robotMapStopSave.setPositionMapId(id);
            robotMapStopSave.setStopType(ZeroOneEnum.ZERO.getType());
            robotMapStopService.createMapStop(robotMapStopSave);
        }

        informationService.sendEmergencyStopOrRecoveryToRobot(robotSimulationPose, robotNos, str);
        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                .operateAction(mapStr)
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);
    }


    @Override
    public List<PositionMapDO> getAllMap() {
        return positionMapMapper.selectList(new LambdaQueryWrapperX<PositionMapDO>().orderByDesc(PositionMapDO::getId));
    }

    @Override
    public Map<Integer, List<PositionMapDTO>> getPositionMapList() {
        List<PositionMapDO> allMap = getAllMap();
        if (ObjectUtil.isEmpty(allMap)) {
            return Collections.emptyMap();
        }

        List<PositionMapDTO> list = BeanUtils.toBean(allMap, PositionMapDTO.class);
        List<Long> stopMapIds = robotMapStopService.getStopMapIds();
        if (ObjectUtil.isEmpty(stopMapIds)) {
            return list.stream().collect(Collectors.groupingBy(PositionMapDTO::getFloor));
        }

        for (PositionMapDTO positionMap : list) {
            if (stopMapIds.contains(positionMap.getId())) {
                positionMap.setStopOrRestore(ZeroOneEnum.ONE.getType());
            }
        }

        return list.stream().collect(Collectors.groupingBy(PositionMapDTO::getFloor));
    }

    /**
     * 远遥获取地图和车辆信息
     *
     * @param mapId
     * @return
     */
    @Override
    public List<RemoteRobotDTO> getRemoteAreaRobotByMapId(Long mapId) {

        PositionMapDO positionMapDO = positionMapMapper.selectById(mapId);
        List<String> robotNos =
                informationService.getRobotByFloorAndArea(String.valueOf(positionMapDO.getFloor()), positionMapDO.getArea());
        if (ObjectUtil.isEmpty(robotNos)) {
            return new ArrayList<>();
        }

        List<RobotInformationDO> allRobot = informationService.getRobotInformationByRobotNos(robotNos);

        List<RobotDoingTaskDTO> robotDoingTask = taskDetailService.getRobotDoingTaskNo(null);

        List<RemoteControllerInformationDO> remoteControllerInformations = controllerInformationService.getAllRemoteController();

        Map<String, RobotInformationDO> robotMap = null;
        if (ObjectUtil.isNotEmpty(allRobot)) {
            robotMap =
                    allRobot.stream().collect(Collectors.toMap(RobotInformationDO::getRobotNo, Function.identity()));
        }

        Map<String, RobotDoingTaskDTO> robotDoingTaskMap = null;
        if (ObjectUtil.isNotEmpty(robotDoingTask)) {
            robotDoingTaskMap = robotDoingTask.stream().collect(Collectors.toMap(RobotDoingTaskDTO::getRobotNo, Function.identity(), (v1, v2) -> v1));
        }

        Map<String, RemoteControllerInformationDO> remoteMap = null;
        if (ObjectUtil.isNotEmpty(remoteControllerInformations)) {
            remoteMap = remoteControllerInformations.stream().collect(Collectors.toMap(RemoteControllerInformationDO::getRobotNo, Function.identity()));
        }

        return getRemoteSingleMapInfomation(robotMap, robotNos,
                robotDoingTaskMap,
                remoteMap);
    }

    /**
     * 获取地图的文件名
     *
     * @param floor
     * @param area
     * @return
     */
    @Override
    public String getMapFileNameByFloorAndAreaName(Long floor, String area) {
        PositionMapDO positionMapDO = positionMapMapper.selectOne(new LambdaQueryWrapperX<PositionMapDO>()
                .eq(PositionMapDO::getFloor, floor)
                .eq(PositionMapDO::getArea, area)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(positionMapDO)) {
            return null;
        }
        String pngUrl = positionMapDO.getPngUrl();
        int startOne = pngUrl.lastIndexOf("\\");
        int startTwo = pngUrl.lastIndexOf("/");
        if (ObjectUtil.isNotEmpty(startTwo)) {
            startTwo = startTwo + 1;
        }
        int start = Math.max(startOne, startTwo);
        int end = pngUrl.lastIndexOf(".");
        return pngUrl.substring(start, end);
    }

    @Override
    public void updateNoSort(Long id, Long locationNoSort) {
        PositionMapDO data = new PositionMapDO();
        data.setId(id);
        data.setLocationNoSort(locationNoSort);
        positionMapMapper.updateById(data);
    }

    private List<RemoteRobotDTO> getRemoteSingleMapInfomation(Map<String, RobotInformationDO> robotMap, List<String> robotNos,
                                                              Map<String, RobotDoingTaskDTO> robotDoingTaskMap,
                                                              Map<String, RemoteControllerInformationDO> remoteMap) {
        RemoteRobotDTO automatic = new RemoteRobotDTO();
        RemoteRobotDTO handMovement = new RemoteRobotDTO();
        RemoteRobotDTO free = new RemoteRobotDTO();
        List<RemoteRobotDetailDTO> automaticDetail = new ArrayList<>();
        List<RemoteRobotDetailDTO> handMovementDetail = new ArrayList<>();
        List<RemoteRobotDetailDTO> freeDetail = new ArrayList<>();

        for (String robotNo : robotNos) {
            RobotInformationDO robotInformation = robotMap.get(robotNo);
            if (ObjectUtil.isEmpty(robotInformation)) {
                continue;
            }
            RemoteRobotDetailDTO remoteRobotDetail = BeanUtils.toBean(robotInformation, RemoteRobotDetailDTO.class);
            if (ObjectUtil.isNotEmpty(robotDoingTaskMap) && ObjectUtil.isNotEmpty(robotDoingTaskMap.get(robotNo))) {
                remoteRobotDetail.setTaskNo(robotDoingTaskMap.get(robotNo).getTaskNo());
            } else if (RobotStatusEnum.DOING.getType().equals(robotInformation.getRobotStatus())) {
                remoteRobotDetail.setTaskNo("车辆正在做移动任务");
            } else if (RobotStatusEnum.CHARGE.getType().equals(robotInformation.getRobotStatus())) {
                remoteRobotDetail.setTaskNo("车辆正在做充电任务");
            }

            if (ObjectUtil.isNotEmpty(remoteMap) && ObjectUtil.isNotEmpty(remoteMap.get(robotNo))) {
                remoteRobotDetail.setRemoteMode(remoteMap.get(robotNo).getRemoteMode());
            }

            if (RemoteModeEnum.AUTOMATIC.getType().equals(remoteRobotDetail.getRemoteMode())) {
                automaticDetail.add(remoteRobotDetail);
            } else if (RemoteModeEnum.HAND_MOVEMENT.getType().equals(remoteRobotDetail.getRemoteMode())) {
                handMovementDetail.add(remoteRobotDetail);
            } else {
                freeDetail.add(remoteRobotDetail);
            }
        }

        automatic.setRemoteMode(RemoteModeEnum.AUTOMATIC.getType());
        automatic.setRobotQuantity(automaticDetail.size());
        automatic.setRobotList(automaticDetail);

        handMovement.setRemoteMode(RemoteModeEnum.HAND_MOVEMENT.getType());
        handMovement.setRobotQuantity(handMovementDetail.size());
        handMovement.setRobotList(handMovementDetail);

        free.setRemoteMode(RemoteModeEnum.FREE.getType());
        free.setRobotQuantity(freeDetail.size());
        free.setRobotList(freeDetail);

        return Arrays.asList(automatic, handMovement, free);
    }
}
