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

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.mqtt.api.common.CommonApi;
import cn.iocoder.yudao.module.system.api.path.vo.RobotClosePathPlantingDTO;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteExceptionTaskDetailDTO;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteTaskQueryDTO;
import cn.iocoder.yudao.module.system.config.mqtt.util.MqttUtils;
import cn.iocoder.yudao.module.system.constant.path.PathPlanningTopicConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.detail.RobotDoingTaskDTO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.statistics.dto.RobotTaskManualInterventionDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.log.RobotTaskDetailActionLogDO;
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.RobotTaskDetailDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnMsgDO;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskDetailMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskMapper;
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.robot.RobotTaskDetailStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotTaskStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotTaskTypeEnum;
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.enums.robot.task.RobotTaskManualInterventionEnum;
import cn.iocoder.yudao.module.system.enums.robot.task.RobotTaskStageEnum;
import cn.iocoder.yudao.module.system.service.log.RobotTaskDetailActionLogService;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.path.PathPlanningService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

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

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;


import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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 RobotTaskDetailServiceImpl implements RobotTaskDetailService {

    @Resource
    private RobotTaskDetailMapper taskDetailMapper;

    @Resource
    private RobotTaskMapper robotTaskMapper;

    @Resource
    private RobotTaskDetailActionLogService taskDetailActionLogService;

    @Resource
    private RobotInformationService informationService;

    @Resource
    private RobotWarnMsgService warnMsgService;

   /* @Resource
    private CommonApi commonApi;*/

    @Autowired
    private MqttUtils mqttUtils;

    @Resource
    private UserOperationLogService userOperationLogService;

    @Resource
    private PathPlanningService pathPlanningService;

    @Override
    public Long createTaskDetail(RobotTaskDetailSaveReqVO createReqVO) {
        // 插入
        RobotTaskDetailDO taskDetail = BeanUtils.toBean(createReqVO, RobotTaskDetailDO.class);
        taskDetailMapper.insert(taskDetail);
        // 返回
        return taskDetail.getId();
    }

    @Override
    public void updateTaskDetail(RobotTaskDetailSaveReqVO updateReqVO) {
        // 校验存在
        validateTaskDetailExists(updateReqVO.getId());
        RobotTaskDetailDO robotTaskDetailDO = taskDetailMapper.selectById(updateReqVO.getId());
        if (ObjectUtil.isNotEmpty(updateReqVO.getRobotNo()) &&
                !RobotTaskDetailStatusEnum.NEW.getType().equals(robotTaskDetailDO.getTaskStatus())
                && !robotTaskDetailDO.getTaskStatus().equals(updateReqVO.getTaskStatus())) {
            throw exception(TASK_DETAIL_CHANGE_ROBOT);
        }
        // 更新
        RobotTaskDetailDO updateObj = BeanUtils.toBean(updateReqVO, RobotTaskDetailDO.class);
        taskDetailMapper.updateById(updateObj);
    }

    @Override
    public void deleteTaskDetail(Long id) {
        // 校验存在
        validateTaskDetailExists(id);
        // 删除
        taskDetailMapper.deleteById(id);
    }

    private void validateTaskDetailExists(Long id) {
        if (taskDetailMapper.selectById(id) == null) {
            throw exception(TASK_DETAIL_NOT_EXISTS);
        }
    }

    @Override
    public RobotTaskDetailDO getTaskDetail(Long id) {
        return taskDetailMapper.selectById(id);
    }

    @Override
    public PageResult<RobotTaskDetailDO> getTaskDetailPage(RobotTaskDetailPageReqVO pageReqVO) {
        return taskDetailMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertRobotDetailList(List<RobotTaskDetailAddVO> taskDetailList) {
        List<RobotTaskDetailDO> bean = BeanUtils.toBean(taskDetailList, RobotTaskDetailDO.class);
        taskDetailMapper.insertBatch(bean);
//        taskDetailMapper.insertBatchList(taskDetailList);
    }

    @Override
    public RobotTaskDetailDO closeTaskDetail(Long taskDetailId) {
        RobotTaskDetailDO robotTaskDetailDO = taskDetailMapper.selectById(taskDetailId);
        robotTaskDetailDO.setTaskStatus(RobotTaskDetailStatusEnum.ABNORMAL.getType());
        taskDetailMapper.updateById(robotTaskDetailDO);

        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.selectList(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                .eq(RobotTaskDetailDO::getRobotTaskId, robotTaskDetailDO.getRobotTaskId())
                .in(RobotTaskDetailDO::getTaskStatus, RobotTaskStatusEnum.NEW.getType(), RobotTaskStatusEnum.DOING.getType()));
        if (ObjectUtil.isEmpty(taskDetailDOS)) {
            RobotTaskDO robotTask = RobotTaskDO.builder()
                    .id(robotTaskDetailDO.getRobotTaskId())
                    .taskStatus(RobotTaskStatusEnum.Exc.getType()).build();
            robotTaskMapper.updateRobot(robotTask);
        }
        log.info("车机上报异常， 把任务取消 :{}", taskDetailId);
        return robotTaskDetailDO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void manuallyCompleted(Long taskDetailId, String str, Integer type) {
        RobotTaskDetailDO robotTaskDetailDO = taskDetailMapper.selectById(taskDetailId);
        Long taskStage = robotTaskDetailDO.getTaskStage();
        robotTaskDetailDO.setTaskStatus(RobotTaskDetailStatusEnum.DONE.getType());
        robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.MANUALLY_COMPLETED.getType());
        robotTaskDetailDO.setOccurError(ZeroOneEnum.ZERO.getType());

        if (RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(robotTaskDetailDO.getTaskType())
                && RobotTaskManualInterventionEnum.REMOTE_DO_TAKE.getType().equals(robotTaskDetailDO.getManualIntervention())
                && RobotTaskManualInterventionEnum.REMOTE_TASK_DONE.getType().equals(type)) {
            type = RobotTaskManualInterventionEnum.REMOTE_TAKE_TASK.getType();
        }
        robotTaskDetailDO.setManualIntervention(type);
        robotTaskDetailDO.setManualInterventionTime(LocalDateTime.now());

        taskDetailMapper.updateById(robotTaskDetailDO);

        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.selectList(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                .eq(RobotTaskDetailDO::getRobotTaskId, robotTaskDetailDO.getRobotTaskId())
                .in(RobotTaskDetailDO::getTaskStatus, RobotTaskStatusEnum.NEW.getType(), RobotTaskStatusEnum.DOING.getType()));
        if (ObjectUtil.isEmpty(taskDetailDOS)) {
            RobotTaskDO robotTask = RobotTaskDO.builder()
                    .id(robotTaskDetailDO.getRobotTaskId())
                    .taskStatus(RobotTaskStatusEnum.DONE.getType()).build();
            robotTaskMapper.updateRobot(robotTask);
        }

        UserOperationLogSaveReqVO build = UserOperationLogSaveReqVO.builder()
                .operateAction("任务id " + taskDetailId + str + robotTaskDetailDO.getRobotNo())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(build);

        RobotTaskDetailActionLogDO actionLog = taskDetailActionLogService.getLastTaskByRobotNo(robotTaskDetailDO.getRobotNo(), CommandIdEnum.TASK.getType());
        if (ObjectUtil.isEmpty(actionLog) || !actionLog.getTaskDetailId().equals(taskDetailId)) {
            return;
        }

        informationService.setRobotFree(robotTaskDetailDO.getRobotNo());

        actionLog.setActionStatus(ActionStatusEnum.DONE.getType());
        taskDetailActionLogService.updateTaskDetailActionLogs(Collections.singletonList(actionLog));
        taskDetailActionLogService.setPreviousTaskDoneByOrderId(taskDetailId);

        if (RobotTaskStageEnum.DONE.getType().equals(taskStage)
                || RobotTaskStageEnum.CLOSE.getType().equals(taskStage)
                || RobotTaskStageEnum.MANUALLY_COMPLETED.getType().equals(taskStage)) {
            return;
        }

        String mac = informationService.getMacByRobotNo(robotTaskDetailDO.getRobotNo());
        informationService.robotCloseTaskDetail(String.valueOf(taskDetailId), mac, actionLog.getCommandType());

        RobotClosePathPlantingDTO closePathPlanting = RobotClosePathPlantingDTO.builder()
                .robotNo(robotTaskDetailDO.getRobotNo())
                .id(robotTaskDetailDO.getId().toString())
                .build();
//        commonApi.commonMethod(closePathPlanting, PathPlanningTopicConstant.KILL_TASK);
        mqttUtils.pub(PathPlanningTopicConstant.KILL_TASK, JSON.toJSONString(closePathPlanting));
    }

    @Override
    public List<RobotTaskDetailDO> getDoingTaskDetailByLocationIds(List<Long> ids) {
        return taskDetailMapper.getDoingTaskDetailByLocationIds(ids);
    }

    @Override
    public String getTaskNoByDetailId(Long taskDetailId) {
        return taskDetailMapper.getTaskNoByDetailId(taskDetailId);
    }

    @Override
    public List<Long> getDoIngTaskItemIdsByItemIds(List<Long> pointList) {
        return taskDetailMapper.getDoIngTaskItemIdsByItemIds(pointList);
    }

    @Override
    public void setTaskDetailError(Long id) {
        RobotTaskDetailDO detailDO = taskDetailMapper.selectById(id);
        RobotTaskDetailDO robotTaskDetailDO = new RobotTaskDetailDO();
        robotTaskDetailDO.setId(id);
        if (RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(detailDO.getTaskType())) {
            if (RobotTaskStageEnum.UN_START.getType().equals(detailDO.getTaskStage())
                    || RobotTaskStageEnum.GO_TAKE.getType().equals(detailDO.getTaskStage())
                    || RobotTaskStageEnum.TAKEING.getType().equals(detailDO.getTaskStage())) {
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.TAKEING_EXCEPTION.getType());
            } else {
                robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.RELEASEING_EXCEPTION.getType());
            }
        } else if (RobotTaskTypeEnum.TAKE.getType().equals(detailDO.getTaskType())) {
            robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.TAKEING_EXCEPTION.getType());
        } else if (RobotTaskTypeEnum.RELEASE.getType().equals(detailDO.getTaskType())) {
            robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.RELEASEING_EXCEPTION.getType());
        } else {
            robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.EXCEPTION.getType());
        }
        robotTaskDetailDO.setOccurError(ZeroOneEnum.ONE.getType());
        taskDetailMapper.updateRobotDetailById(robotTaskDetailDO);

        List<RobotTaskDetailDO> taskDetailDOS = taskDetailMapper.selectList(new LambdaQueryWrapperX<RobotTaskDetailDO>()
                .eq(RobotTaskDetailDO::getRobotTaskId, detailDO.getRobotTaskId()));
        if (taskDetailDOS.size() > 1) {
            return;
        }
        RobotTaskDO robotTaskDO = new RobotTaskDO();
        robotTaskDO.setId(detailDO.getRobotTaskId());
        robotTaskDO.setTaskStatus(RobotTaskDetailStatusEnum.ABNORMAL.getType());
        robotTaskMapper.updateRobot(robotTaskDO);
    }

    /**
     * 获取机器人正在做的任务
     *
     * @return
     */
    @Override
    public List<RobotDoingTaskDTO> getRobotDoingTaskNo(String robotNo) {
        return taskDetailMapper.getRobotDoingTaskNo(robotNo);
    }


    /**
     * 远遥查询异常的车辆
     *
     * @param pageReqVO
     * @return
     */
    @Override
    public PageResult<RemoteExceptionTaskDetailDTO> getExceptionTaskDetail(RemoteTaskQueryDTO pageReqVO) {
        IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<RemoteExceptionTaskDetailDTO> page = taskDetailMapper.getExceptionTaskDetail(mpPage, pageReqVO);
        PageResult<RemoteExceptionTaskDetailDTO> dataPage = new PageResult<>();
        dataPage.setTotal(page.getTotal());
        if (ObjectUtil.isEmpty(page.getRecords())) {
            return dataPage;
        }

        List<RobotInformationDO> allRobot = informationService.getAllRobot();
        Map<String, String> map = null;
        if (ObjectUtil.isNotEmpty(allRobot)) {
            map = allRobot.stream().collect(Collectors.toMap(RobotInformationDO::getRobotNo, RobotInformationDO::getUrl));
        }

        List<Long> detailIds = page.getRecords().stream().map(RemoteExceptionTaskDetailDTO::getId).collect(Collectors.toList());

        List<RobotWarnMsgDO> warnMsgs = warnMsgService.getWarnMsgByDetailIds(detailIds);
        Map<Long, String> warnMsgMap = null;
        if (ObjectUtil.isNotEmpty(warnMsgs)) {
            warnMsgMap = warnMsgs.stream().collect(Collectors.toMap(RobotWarnMsgDO::getTaskDetailId, RobotWarnMsgDO::getWarnMsg, (existingValue, newValue) -> existingValue));
        }

        for (RemoteExceptionTaskDetailDTO record : page.getRecords()) {
            if (ObjectUtil.isNotEmpty(map)) {
                record.setUrl(map.get(record.getRobotNo()));
            }
            if (ObjectUtil.isNotEmpty(warnMsgMap)) {
                record.setWarnMsg(warnMsgMap.get(record.getId()));
            }
        }

        dataPage.setList(page.getRecords());
        return dataPage;
    }

    /**
     * 取货完成
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remoteTaskTakeDone(Long taskDetailId) {
        RobotTaskDetailDO robotTaskDetailDO = taskDetailMapper.selectById(taskDetailId);
        String str = " 远遥点击取货完成 ";
        if (RobotTaskTypeEnum.TAKE.getType().equals(robotTaskDetailDO.getTaskType())) {
            manuallyCompleted(taskDetailId, str, RobotTaskManualInterventionEnum.REMOTE_DO_TAKE.getType());
        } else if (RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(robotTaskDetailDO.getTaskType())) {

            if (!RobotTaskStageEnum.UN_START.getType().equals(robotTaskDetailDO.getTaskStage())
                    && !RobotTaskStageEnum.GO_TAKE.getType().equals(robotTaskDetailDO.getTaskStage())
                    && !RobotTaskStageEnum.TAKEING.getType().equals(robotTaskDetailDO.getTaskStage())) {
                log.info("远遥点击取货完成时, 任务已经取完货 :{}", JSON.toJSONString(robotTaskDetailDO));
                throw exception(TASK_NOT_TAKE_RELEASE);
            }

            robotTaskDetailDO.setTaskStage(RobotTaskStageEnum.GO_RELEASE.getType());
            taskDetailMapper.updateById(robotTaskDetailDO);

            UserOperationLogSaveReqVO build = UserOperationLogSaveReqVO.builder()
                    .operateAction("任务id " + taskDetailId + str + robotTaskDetailDO.getRobotNo())
                    .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
            userOperationLogService.createUserOperationLog(build);

            taskDetailActionLogService.setPreviousTaskDoneByOrderId(taskDetailId);

            pathPlanningService.updateBehavior(String.valueOf(taskDetailId), robotTaskDetailDO.getRobotNo()
                    , "", PathIsReachEnum.END_WORK.getType());
        } else {
            throw exception(TASK_NOT_TAKE_RELEASE);
        }

    }

    /**
     * 统计任务人工完成/自动完成
     *
     * @param type type  1:周, 2:月,  3:季度
     * @return
     */
    @Override
    public RobotTaskManualInterventionDTO robotTaskAutomaticArtificial(String type) {
        RobotTaskManualInterventionDTO data = taskDetailMapper.getRobotTaskAutomaticArtificial(type);
        if (ObjectUtil.isEmpty(data)) {
            return new RobotTaskManualInterventionDTO();
        }
        int total = data.getArtificialDoneNum() + data.getAutomaticDoneNum();
        if (total == 0) {
            return new RobotTaskManualInterventionDTO();
        }
        int artificialDone = data.getArtificialDoneNum() * 100 / total;
        int automaticDone = data.getAutomaticDoneNum() * 100 / total;

        if ((automaticDone + artificialDone) < 100 && artificialDone > 0) {
            artificialDone = artificialDone + 1;
        } else if ((automaticDone + artificialDone) < 100 && automaticDone > 0) {
            automaticDone = automaticDone + 1;
        }

        data.setArtificialDone(artificialDone);
        data.setAutomaticDone(automaticDone);
        return data;
    }


}