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

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotStatusDataErrorDTO;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotReactiveStatusDTO;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.constant.area.FloorAreaConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.dal.dataobject.log.RobotTaskDetailActionLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnCodeMappingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnMsgDO;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnCodeMappingMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnMsgMapper;
import cn.iocoder.yudao.module.system.enums.robot.RobotWarnType;
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.service.log.RobotTaskDetailActionLogService;
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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

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

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private RobotWarnMsgService warnMsgService;

    @Resource
    private RobotWarnMsgMapper warnMsgMapper;

    @Resource
    private RobotWarnCodeMappingMapper warnCodeMappingMapper;

    @Autowired
    private RobotInformationService robotInformationService;

    @Resource
    private RobotTaskDetailActionLogService taskDetailActionLogService;

    @Resource
    private RobotTaskDetailService taskDetailService;

    @Override
    public void robotReactiveStatus(String message) {
        TenantContextHolder.setTenantId(1L);
//        log.info("车辆所在楼层和异常信息 :{}", message);
        RobotReactiveStatusDTO data = JSON.parseObject(message, RobotReactiveStatusDTO.class);
        String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + data.getMac();
        String robotNo = robotInformationService.getRobotNoByMac(data.getMac());

        Object o = redisUtil.get(floorAreaKey);
        FloorZoneDTO floorZone = new FloorZoneDTO();
        if (ObjectUtil.isNotEmpty(o)) {
            floorZone = JSON.parseObject((String) o, FloorZoneDTO.class);
            String oldFloorArea = floorZone.getFloor() + CommonConstant.SYMBOL + floorZone.getArea();
            redisUtil.hdel(oldFloorArea, robotNo);

            String newFloorArea = data.getFloorZone().getFloor() + CommonConstant.SYMBOL + data.getFloorZone().getArea();
            String key = FloorAreaConstant.FLOOR_AREA_ROBOT + floorZone.getFloor() + CommonConstant.SYMBOL + floorZone.getArea();
            if (!oldFloorArea.equals(newFloorArea)) {
                redisUtil.hdel(key, robotNo);
            }
        }

        floorZone.setArea(data.getFloorZone().getArea());
        floorZone.setFloor(data.getFloorZone().getFloor());
        floorZone.setLinearSpeed(data.getAgvSpeed().getLinearSpeed());

        redisUtil.set(floorAreaKey, JSON.toJSONString(floorZone));
        Map<String, Object> map = new HashMap<>();
        String value = floorZone.getFloor() + CommonConstant.SYMBOL + floorZone.getArea();
        map.put(robotNo, value);
        redisUtil.hmset(value, map);

        String speedKey = RobotTaskChcheConstant.ROBOT_SPEED_FORK_HEIGHT + robotNo;
        redisUtil.set(speedKey, message);

        // -- get 老的数据 - 看有没有 - 有的话 - 对比下 - 如果相同 - 更新hashMap中key的value
        // - 如果不相同的话 - 更新当前redis数据 - 然后 - 根据老的数据 去 hashMapRedis 中删除 这个key的数据
        // - 然后插入到 对应的区域的hashMap中

        //机器人异常等级
        if (ObjectUtil.isEmpty(data.getErrCode())) {
            String errorLevelKey = RobotTaskChcheConstant.ROBOT_ERROR_LEVEL + data.getMac();
            String errorMsgKey = RobotTaskChcheConstant.ROBOT_ERROR_MSG + data.getMac();
            redisUtil.del(errorLevelKey);
            redisUtil.del(errorMsgKey);
        } else {
            addRobotErrorMsg(data);
        }
    }

    /**
     * 添加异常
     *
     * @param data
     */
    private void addRobotErrorMsg(RobotReactiveStatusDTO data) {
        String robotNo = robotInformationService.getRobotNoByMac(data.getMac());
        List<RobotStatusDataErrorDTO> errCode = data.getErrCode();
        Set<String> warnCodes =
                errCode.stream().map(RobotStatusDataErrorDTO::getErrorCode).collect(Collectors.toSet());
        List<RobotWarnCodeMappingDO> robotWarnCodeMappingDOS =
                warnCodeMappingMapper.selectList(new LambdaQueryWrapper<RobotWarnCodeMappingDO>()
                        .in(RobotWarnCodeMappingDO::getWarnCode, warnCodes));
        if (ObjectUtil.isEmpty(robotWarnCodeMappingDOS)) {
            log.info("查不对应编号的告警信息 :{}", JSON.toJSONString(data));
            return;
        }

        Map<String, RobotWarnCodeMappingDO> warnCodeMapping =
                robotWarnCodeMappingDOS.stream().collect(Collectors.toMap(RobotWarnCodeMappingDO::getWarnCode, Function.identity()));

        List<RobotWarnMsgDO> warnMsgDOS = new ArrayList<>();

        //机器人异常等级
        String errorLevelKey = RobotTaskChcheConstant.ROBOT_ERROR_LEVEL + data.getMac();

        String errorMsgKey = RobotTaskChcheConstant.ROBOT_ERROR_MSG + data.getMac();
        RobotTaskDetailActionLogDO lastTaskByRobotNo = taskDetailActionLogService.getLastTaskByRobotNo(robotNo, CommandIdEnum.TASK.getType());

        int level = 0;
        String msg = "";
        for (RobotStatusDataErrorDTO robotStatusData : errCode) {
            RobotWarnCodeMappingDO mappingDOS = warnCodeMapping.get(robotStatusData.getErrorCode());
            if (ObjectUtil.isEmpty(mappingDOS)) {
                log.info("当前告警类型查不到对应的告警信息 :{}", robotStatusData.getErrorCode());
                continue;
            }
            RobotWarnMsgDO warnMsg = RobotWarnMsgDO.builder().warnLevel(mappingDOS.getWarnLevel())
                    .warnCode(robotStatusData.getErrorCode())
                    .robotNo(robotNo)
                    .warnType(RobotWarnType.ROBOT_WARN.getType())
                    .warnMsg(robotNo+"号车" + CommonConstant.SYMBOL + mappingDOS.getWarnMsg())
                    .warnSolve(mappingDOS.getWarnSolve())
                    .build();

            if (ObjectUtil.isNotEmpty(lastTaskByRobotNo) && ActionStatusEnum.DOING.getType().equals(lastTaskByRobotNo.getActionStatus())) {
                warnMsg.setTaskNo(lastTaskByRobotNo.getTaskNo());
                warnMsg.setTaskDetailId(lastTaskByRobotNo.getTaskDetailId());
            }

            warnMsgDOS.add(warnMsg);

            if (level < mappingDOS.getWarnLevel()) {
                level = mappingDOS.getWarnLevel();
                msg = warnMsg.getWarnMsg();
            }
        }
        redisUtil.set(errorLevelKey, level);
        redisUtil.set(errorMsgKey, msg);

        if (ObjectUtil.isNotEmpty(lastTaskByRobotNo) && ActionStatusEnum.DOING.getType().equals(lastTaskByRobotNo.getActionStatus())
                && 4 == level && ObjectUtil.isNotEmpty(lastTaskByRobotNo.getTaskDetailId())) {
            taskDetailService.setTaskDetailError(lastTaskByRobotNo.getTaskDetailId());
        }

        warnMsgService.sendWarnMsgToWebsocket(msg);

        warnMsgMapper.insertBatch(warnMsgDOS);
    }
}
