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

import cn.hutool.core.util.ObjectUtil;
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.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.mapstop.RobotMapStopPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.mapstop.RobotMapStopSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotMapStopDO;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotMapStopMapper;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotCommandTypeEnum;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


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

/**
 * 车辆(地图)急停记录 Service 实现类
 *
 * @author 陈宾顺
 */
@Service
@Validated
public class RobotMapStopServiceImpl extends ServiceImpl<RobotMapStopMapper, RobotMapStopDO> implements RobotMapStopService {

    @Resource
    private RobotMapStopMapper mapStopMapper;

    @Resource
    private RobotInformationService informationService;

    @Resource
    private PositionMapMapper positionMapMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UserOperationLogService userOperationLogService;

    @Override
    public Long createMapStop(RobotMapStopSaveReqVO createReqVO) {
        // 插入
        RobotMapStopDO mapStop = BeanUtils.toBean(createReqVO, RobotMapStopDO.class);
        mapStopMapper.insert(mapStop);
        // 返回
        return mapStop.getId();
    }

    @Override
    public void updateMapStop(RobotMapStopSaveReqVO updateReqVO) {
        // 校验存在
        validateMapStopExists(updateReqVO.getId());
        // 更新
        RobotMapStopDO updateObj = BeanUtils.toBean(updateReqVO, RobotMapStopDO.class);
        mapStopMapper.updateById(updateObj);
    }

    @Override
    public void deleteMapStop(Long id) {
        // 校验存在
        validateMapStopExists(id);
        // 删除
        mapStopMapper.deleteById(id);
    }

    private void validateMapStopExists(Long id) {
        if (mapStopMapper.selectById(id) == null) {
            throw exception(MAP_STOP_NOT_EXISTS);
        }
    }

    @Override
    public RobotMapStopDO getMapStop(Long id) {
        return mapStopMapper.selectById(id);
    }

    @Override
    public PageResult<RobotMapStopDO> getMapStopPage(RobotMapStopPageReqVO pageReqVO) {
        return mapStopMapper.selectPage(pageReqVO);
    }

    @Override
    public List<Long> getStopMapIds() {
        List<RobotMapStopDO> positionMapItems = mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, ZeroOneEnum.ZERO.getType()));
        if (ObjectUtil.isEmpty(positionMapItems)) {
            return new ArrayList<>();
        }

        return positionMapItems.stream()
                .map(RobotMapStopDO::getPositionMapId)
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getStopRobotNoByMapIds(Long id) {
        List<RobotMapStopDO> positionMapItems = mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, ZeroOneEnum.ONE.getType())
                .eq(RobotMapStopDO::getPositionMapId, id));
        if (ObjectUtil.isEmpty(positionMapItems)) {
            return new ArrayList<>();
        }

        return positionMapItems.stream()
                .map(RobotMapStopDO::getRobotNo)
                .collect(Collectors.toList());
    }

    /**
     * @param id
     * @param robotNos
     */
    @Override
    public void createRobotMapStop(Long id, List<String> robotNos) {
        List<RobotMapStopDO> list = new ArrayList<>();
        for (String robotNo : robotNos) {
            RobotMapStopDO mapStop = new RobotMapStopDO();
            mapStop.setPositionMapId(id);
            mapStop.setRobotNo(robotNo);
            mapStop.setStopType(ZeroOneEnum.ONE.getType());
            list.add(mapStop);
        }
        mapStopMapper.insertBatch(list);
    }

    @Override
    public void deleteRobotMapStopByMapId(Long id) {
        mapStopMapper.deleteRobotMapStopByMapId(id);
    }

    @Override
    public List<RobotMapStopDO> getByMapId(Long id) {
        List<RobotMapStopDO> positionMapItems = mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, ZeroOneEnum.ZERO.getType())
                .eq(RobotMapStopDO::getPositionMapId, id));
        return positionMapItems;
    }

    @Override
    public List<RobotMapStopDO> getAllRobotMapStops(Integer type) {
        return mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, type));
    }

    @Override
    public List<RobotMapStopDO> getStopRobotNoByRobotNo(String robotNo) {
        return mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, ZeroOneEnum.ONE.getType())
                .eq(RobotMapStopDO::getRobotNo, robotNo));
    }

    /**
     * 远遥暂停车辆
     *
     * @param robotNo
     * @return
     */
    @Override
    public void remoteStopRobot(String robotNo) {
        List<RobotMapStopDO> stopRobotNoByRobotNo = getStopRobotNoByRobotNo(robotNo);
        if (ObjectUtil.isNotEmpty(stopRobotNoByRobotNo)) {
            throw exception(ROBOT_ALREADY_STOP);
        }

        RobotAcceptTaskDTO robotSimulationPose = new RobotAcceptTaskDTO();
        robotSimulationPose.setExecutionType(RobotCommandTypeEnum.PAUSE.getType());
        List<String> list = Collections.singletonList(robotNo);
        informationService.sendEmergencyStopOrRecoveryToRobot(robotSimulationPose, list, "远遥暂停车辆");

        String mac = informationService.getMacByRobotNo(robotNo);
        String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + mac;
        Object o = redisUtil.get(floorAreaKey);

        Long id = -1l;
        if (ObjectUtil.isNotEmpty(o)) {
            FloorZoneDTO floorZone = JSON.parseObject((String) o, FloorZoneDTO.class);
            PositionMapDO positionMap = positionMapMapper.selectOne(new LambdaQueryWrapperX<PositionMapDO>()
                    .eq(PositionMapDO::getFloor, floorZone.getFloor())
                    .eq(PositionMapDO::getArea, floorZone.getArea()));
            if (ObjectUtil.isNotEmpty(positionMap)) {
                id = positionMap.getId();
            }
        }

        createRobotMapStop(id, list);

    }

    /**
     * 根据车辆编号删除
     *
     * @param robotNos
     */
    @Override
    public void deleteRobotMapStopByRobotNos(List<String> robotNos) {
        mapStopMapper.deleteRobotMapStopByRobotNos(robotNos);
    }

    /**
     * 远遥恢复车辆
     *
     * @param robotNo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remoteRecoveryRobot(String robotNo) {
        List<RobotMapStopDO> stopRobotNoByRobotNo = getStopRobotNoByRobotNo(robotNo);
        if (ObjectUtil.isEmpty(stopRobotNoByRobotNo)) {
            throw exception(ROBOT_ALREADY_RECOVERY);
        }

        Long positionMapId = null;
        for (RobotMapStopDO robotMapStopDO : stopRobotNoByRobotNo) {
            if (robotMapStopDO.getPositionMapId() > 0) {
                positionMapId = robotMapStopDO.getPositionMapId();
            }
        }

        RobotAcceptTaskDTO robotSimulationPose = new RobotAcceptTaskDTO();
        robotSimulationPose.setExecutionType(RobotCommandTypeEnum.CONTINUE.getType());
        List<String> list = Collections.singletonList(robotNo);
        informationService.sendEmergencyStopOrRecoveryToRobot(robotSimulationPose, list, "远遥恢复车辆");

        deleteRobotMapStopByRobotNos(list);

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

        List<RobotMapStopDO> mapStopDOList = mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getPositionMapId, positionMapId));
        //说明此时地图上没有其他被暂停的车辆了
        if (ObjectUtil.isNotEmpty(mapStopDOList) && mapStopDOList.size() == 1 ) {
            PositionMapDO positionMapDO = positionMapMapper.selectById(positionMapId);
            deleteRobotMapStopByMapId(positionMapId);
            UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                    .operateAction(positionMapDO.getFloor() + "层" + positionMapDO.getArea() + " 地图上所有车辆已经恢复,所以把地图也设置为恢复")
                    .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
            userOperationLogService.createUserOperationLog(operationLog);
        }
    }

    @Override
    public List<RobotMapStopDO> getStopRobotNoByRobotNoList(List<String> robotNos) {
        return mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, ZeroOneEnum.ONE.getType())
                .in(RobotMapStopDO::getRobotNo, robotNos));
    }

    @Override
    public void rcsStopRobotAddLog(String robotNo) {
        String mac = informationService.getMacByRobotNo(robotNo);
        List<String> list = Collections.singletonList(robotNo);
        String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + mac;
        Object o = redisUtil.get(floorAreaKey);

        Long id = -1l;
        if (ObjectUtil.isNotEmpty(o)) {
            FloorZoneDTO floorZone = JSON.parseObject((String) o, FloorZoneDTO.class);
            PositionMapDO positionMap = positionMapMapper.selectOne(new LambdaQueryWrapperX<PositionMapDO>()
                    .eq(PositionMapDO::getFloor, floorZone.getFloor())
                    .eq(PositionMapDO::getArea, floorZone.getArea()));
            if (ObjectUtil.isNotEmpty(positionMap)) {
                id = positionMap.getId();
            }
        }

        createRobotMapStop(id, list);
    }

    @Override
    public void rcsDeleteStopRobotAddLog(String robotNo) {
        List<RobotMapStopDO> stopRobotNoByRobotNo = getStopRobotNoByRobotNo(robotNo);
        if (ObjectUtil.isEmpty(stopRobotNoByRobotNo) ){
            return;
        }
        Long mapId = stopRobotNoByRobotNo.get(0).getPositionMapId();
        deleteRobotMapStopByRobotNos(Collections.singletonList(robotNo));
        List<RobotMapStopDO> positionMapItems = mapStopMapper.selectList(new LambdaQueryWrapperX<RobotMapStopDO>()
                .eq(RobotMapStopDO::getStopType, ZeroOneEnum.ONE.getType())
                .eq(RobotMapStopDO::getPositionMapId, mapId));
        if (ObjectUtil.isNotEmpty(positionMapItems)) {
            return;
        }
        mapStopMapper.deleteRobotMapStopByMapId(mapId);
    }


}
