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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.api.robot.websocket.RobotStatusDataPoseDTO;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.controller.admin.bulletinboard.vo.BulletinBoardVO;
import cn.iocoder.yudao.module.system.controller.admin.bulletinboard.vo.RobotElectricityLevelVO;
import cn.iocoder.yudao.module.system.controller.admin.bulletinboard.vo.TaskStatusVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.DeviceStatusInfoVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotInfoStatusVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotInformationStatisticsVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.information.DeviceInformationDO;
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.RobotWarnMsgDO;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotTaskDetailStatusEnum;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import cn.iocoder.yudao.module.system.service.information.DeviceInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 获取看板信息 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class BulletinBoardServiceImpl implements BulletinBoardService {
    @Resource
    private RobotTaskService taskService;
    @Resource
    private RobotWarnMsgService robotWarnMsgService;
    @Resource
    private RobotInformationService robotInformationService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private DeviceInformationService deviceInformationService;
    @Resource
    private DictDataService dictDataService;

    @Override
    public BulletinBoardVO getBulletinBoard() {
        BulletinBoardVO vo = new BulletinBoardVO();
        LocalDateTime now = LocalDateTime.now();
        List<RobotTaskDO> list = taskService.list(new LambdaQueryWrapperX<RobotTaskDO>()
                .ge(RobotTaskDO::getCreateTime, LocalDateTimeUtil.beginOfDay(now)));
        Map<Integer, List<RobotTaskDO>> taskMap = list.stream().collect(Collectors.groupingBy(RobotTaskDO::getTaskStatus));
        // 任务状态
        TaskStatusVO taskStatusVO = new TaskStatusVO();

        // 正在执行
        List<RobotTaskDO> underway = taskMap.get(RobotTaskDetailStatusEnum.DOING.getType());
        //根据时间降序
        if (CollectionUtil.isNotEmpty(underway)) {
            underway.sort((o1, o2) -> o2.getStartTime().compareTo(o1.getStartTime()));
        }
        // 待执行
        List<RobotTaskDO> pendingExecution = taskMap.get(RobotTaskDetailStatusEnum.NEW.getType());
        //根据时间降序
        if (CollectionUtil.isNotEmpty(pendingExecution)) {
            pendingExecution.sort((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()));
        }
        // 已完成
        List<RobotTaskDO> completed = taskMap.get(RobotTaskDetailStatusEnum.DONE.getType());
        // 已取消
        List<RobotTaskDO> cancelled = taskMap.get(RobotTaskDetailStatusEnum.CLOSE.getType());
        taskStatusVO.setPendingExecutionNum(CollectionUtil.isEmpty(pendingExecution) ? 0 : pendingExecution.size());
        taskStatusVO.setUnderwayNum(CollectionUtil.isEmpty(underway) ? 0 : underway.size());
        taskStatusVO.setCompletedNum(CollectionUtil.isEmpty(completed) ? 0 : completed.size());
        taskStatusVO.setCancelledNum(CollectionUtil.isEmpty(cancelled) ? 0 : cancelled.size());
        int abnormalNum = CollectionUtil.isEmpty(taskMap.get(RobotTaskDetailStatusEnum.ABNORMAL.getType())) ? 0 : taskMap.get(RobotTaskDetailStatusEnum.ABNORMAL.getType()).size();
        taskStatusVO.setAbnormalNum(abnormalNum);
        taskStatusVO.setTasksNumber(list.size());
        vo.setTaskStatusVO(taskStatusVO);

        // 获取车辆异常信息
        List<RobotWarnMsgDO> robotWarnMsgDOS = robotWarnMsgService.list(new LambdaQueryWrapperX<RobotWarnMsgDO>()
                .ge(RobotWarnMsgDO::getCreateTime, LocalDateTimeUtil.beginOfDay(now)));

        // 正在执行任务
        vo.setUnderway(underway);
        // 待执行任务
        vo.setPendingExecution(pendingExecution);

        // 车辆状态
        RobotInformationStatisticsVO statisticsVO = robotInformationService.statisticsInformation();
        vo.setStatistics(statisticsVO);
        // 车辆异常信息
        vo.setRobotWarnMsgDOS(robotWarnMsgDOS);
        List<RobotElectricityLevelVO> robotElectricityLevelVOS = new ArrayList<>();
        List<RobotInformationDO> allRobot = robotInformationService.getAllRobot();
        List<RobotInfoStatusVO> agvListStatusInfo = robotInformationService.getAGVListStatusInfo();
        Map<String, RobotInfoStatusVO> map = new HashMap<>();
        if (CollUtil.isNotEmpty(agvListStatusInfo)){
            map = agvListStatusInfo.stream().collect(Collectors.toMap(RobotInfoStatusVO::getMacAddress, Function.identity()));
        }
        for (RobotInformationDO robotInformationDO : allRobot) {
            String pose2dKey = RobotTaskChcheConstant.ROBOT_INFORMATION_POSE_BAT + robotInformationDO.getMacAddress();
            Object object = redisUtil.get(pose2dKey);
            RobotStatusDataPoseDTO robotStatusDataPoseDTO = JSONUtil.toBean((String) object, RobotStatusDataPoseDTO.class);
            if (robotStatusDataPoseDTO != null) {
                RobotElectricityLevelVO robotElectricityLevelVO = new RobotElectricityLevelVO();
                //todo 这里缺少一个状态
                RobotInfoStatusVO item = map.get(robotInformationDO.getMacAddress());
                if (item != null) {
                    BeanUtil.copyProperties(item, robotElectricityLevelVO);
                }
                robotElectricityLevelVO.setRobotNo(robotInformationDO.getRobotNo());
                String socByMac = robotInformationService.getSocByMac(robotInformationDO.getMacAddress(), ZeroOneEnum.ONE.getType());
                if (ObjectUtil.isNotEmpty(socByMac)) {
                    robotElectricityLevelVO.setBatSoc(socByMac);
                }
                robotElectricityLevelVOS.add(robotElectricityLevelVO);
            }
        }
        vo.setRobotElectricityLevelVOS(robotElectricityLevelVOS);
        // - 获取设备类型字典
        List<DictDataDO> deviceTypeList = dictDataService.getDictDataListByDictType("device_type");
        Map<String, DictDataDO> dictMap = deviceTypeList.stream().collect(Collectors.toMap(DictDataDO::getValue, Function.identity()));

        // - 获取所有设备
        List<DeviceInformationDO> deviceInformationDOS = deviceInformationService.list();
        //根据设备类型分组
        Map<Integer, List<DeviceInformationDO>> deviceMap = deviceInformationDOS.stream().collect(Collectors.groupingBy(DeviceInformationDO::getDeviceType));
        List<DeviceStatusInfoVO> deviceStatusInfoVOS = new ArrayList<>();
        for (Map.Entry<Integer, List<DeviceInformationDO>> entry : deviceMap.entrySet()) {
            Integer deviceType = entry.getKey();
            DeviceStatusInfoVO deviceStatusInfoVO = new DeviceStatusInfoVO();
            deviceStatusInfoVO.setDeviceType(deviceType);
            deviceStatusInfoVO.setDefaultImage(dictMap.get(String.valueOf(deviceType)) == null ? null : dictMap.get(String.valueOf(deviceType)).getRemark());
            List<DeviceInformationDO> deviceInformationDOList = entry.getValue();
            if (CollectionUtil.isEmpty(deviceInformationDOList)) {
                deviceStatusInfoVOS.add(deviceStatusInfoVO);
                continue;
            }
            deviceStatusInfoVO.setTotalNum(deviceInformationDOList.size());
            long count = deviceInformationDOList.stream().filter(a -> a.getDeviceStatus().equals(3)).count();
            deviceStatusInfoVO.setNormalNum((int) count);
            deviceStatusInfoVO.setAbnormalNum(deviceStatusInfoVO.getTotalNum() - deviceStatusInfoVO.getNormalNum());
            deviceStatusInfoVOS.add(deviceStatusInfoVO);
        }
        vo.setDeviceStatusInfoVOS(deviceStatusInfoVOS);
        return vo;
    }

}
