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

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
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.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.system.constant.CommonConstant;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnMsgPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnMsgSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.statistics.dto.RobotWarnMsgClassificationDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnMsgDO;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotWarnMsgMapper;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotWarnType;
import cn.iocoder.yudao.module.system.enums.robot.statistics.TimeTypeEnum;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import java.util.*;
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.WARN_MSG_NOT_EXISTS;

/**
 * 机器人告警信息 Service 实现类
 *
 * @author 陈宾顺
 */
@Service
@Validated
@Slf4j
public class RobotWarnMsgServiceImpl extends ServiceImpl<RobotWarnMsgMapper, RobotWarnMsgDO> implements RobotWarnMsgService {

    @Resource
    private RobotWarnMsgMapper warnMsgMapper;

    @Resource
    private PositionMapMapper positionMapMapper;

    @Resource
    public WebSocketSenderApi webSocketSenderApi;

    @Resource
    private UserOperationLogService userOperationLogService;

    /**
     * 别改事物传播
     * @param createReqVO 创建信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public Long createWarnMsg(RobotWarnMsgSaveReqVO createReqVO) {
        // 插入
        RobotWarnMsgDO warnMsg = BeanUtils.toBean(createReqVO, RobotWarnMsgDO.class);
        warnMsgMapper.insert(warnMsg);
        // 返回
        return warnMsg.getId();
    }

    @Override
    public void updateWarnMsg(RobotWarnMsgSaveReqVO updateReqVO) {
        // 校验存在
        validateWarnMsgExists(updateReqVO.getId());
        // 更新
        RobotWarnMsgDO updateObj = BeanUtils.toBean(updateReqVO, RobotWarnMsgDO.class);
        warnMsgMapper.updateById(updateObj);

        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("查看告警信息: " + updateObj.getWarnMsg())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);
    }

    @Override
    public void deleteWarnMsg(Long id) {
        // 校验存在
        validateWarnMsgExists(id);
        // 删除
        warnMsgMapper.deleteById(id);
    }

    private void validateWarnMsgExists(Long id) {
        if (warnMsgMapper.selectById(id) == null) {
            throw exception(WARN_MSG_NOT_EXISTS);
        }
    }

    @Override
    public RobotWarnMsgDO getWarnMsg(Long id) {
        return warnMsgMapper.selectById(id);
    }

    @Override
    public PageResult<RobotWarnMsgDO> getWarnMsgPage(RobotWarnMsgPageReqVO pageReqVO) {
        return warnMsgMapper.selectPage(pageReqVO);
    }

    @Override
    public void sendWarnMsgToWebsocket(Object errorMsg) {
        List<PositionMapDO> positionMapDOS = positionMapMapper.selectList(new LambdaQueryWrapperX<PositionMapDO>());
        if (ObjectUtil.isEmpty(positionMapDOS)) {
            log.info("暂无楼层/区域信息，无法推送数据给前端");
            return;
        }
        for (PositionMapDO positionMapDO : positionMapDOS) {
            webSocketSenderApi.sendObject(positionMapDO.getFloor() + CommonConstant.SYMBOL + positionMapDO.getArea(),
                    WebSocketConstant.AGV_WARN, JSONUtil.toJsonStr(errorMsg));
        }

    }

    @Override
    public void addWarnMsg(String message) {
        if (message.length() > 200) {
            message = message.substring(0, 200);
        }
        RobotWarnMsgDO warnMsg = RobotWarnMsgDO.builder().warnLevel(4)
                .warnCode("DEVICE")
                .robotNo("")
                .warnType(RobotWarnType.PATH.getType())
                .warnMsg(message)
                .warnSolve(message)
                .build();
        warnMsgMapper.insert(warnMsg);
    }

    @Override
    public List<RobotWarnMsgDO> getReadPage() {
        RobotWarnMsgPageReqVO pageReqVO = new RobotWarnMsgPageReqVO();
        pageReqVO.setPageSize(10);
        pageReqVO.setPageNo(0);
        pageReqVO.setReadStatus(ZeroOneEnum.ZERO.getType());
        return warnMsgMapper.selectReadPage(pageReqVO).getList();
    }

    @Override
    public String allRead() {
        warnMsgMapper.updateAllRead();
        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("更新所有告警信息为已读")
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);
        return "更新成功";
    }

    /**
     * 查询这些明细对应的最新的4级告警信息
     *
     * @param detailIds
     * @return
     */
    @Override
    public List<RobotWarnMsgDO> getWarnMsgByDetailIds(List<Long> detailIds) {
        return warnMsgMapper.getFourLevelWarnMsgByDetailIds(detailIds);
    }

    /**
     * 统计故障根因分析   type  1:周, 2:月,  3:季度
     *
     * @param type
     * @return
     */
    @Override
    public Map<String, List<RobotWarnMsgClassificationDTO>> robotWarnMsgClassification(String type) {

        if (TimeTypeEnum.WEEK.getType().equals(type)) {
            List<RobotWarnMsgClassificationDTO> data = warnMsgMapper.getRobotWarnMsgClassification(type);
            if (ObjectUtil.isEmpty(data)) {
                return null;
            }

            Map<String, List<RobotWarnMsgClassificationDTO>> map =
                    data.stream().collect(Collectors.groupingBy(RobotWarnMsgClassificationDTO::getWarnTime));

            Calendar now = Calendar.getInstance();
            now.setTime(new Date());
            for (int i = 0; i < 7; i++) {
                String timeStr = DateUtils.getYYYMMDD(now.getTime());
                if (!map.containsKey(timeStr)) {
                    map.put(timeStr,new ArrayList<>());
                }
                now.set(Calendar.DATE, now.get(Calendar.DATE) - 1);
            }

            return map;
        }

        //季度是90天，分成10份，是9. getMonthData已经扣了1，所以是8
        int i = 8;
        if (TimeTypeEnum.MONTH.getType().equals(type)) {
            i= 2;
        }

        return getMonthData(i);
    }

    /**
     * 按月查询
     *
     * @param day
     * @return
     */
    private LinkedHashMap<String, List<RobotWarnMsgClassificationDTO>> getMonthData(int day) {

        Calendar now = Calendar.getInstance();
        now.setTime(new Date());
        now.set(Calendar.DATE, now.get(Calendar.DATE) + 1);

        LinkedHashMap<String, List<RobotWarnMsgClassificationDTO>> map = new LinkedHashMap<>();

        for (int i = 0; i < 10; i++) {
            Date startDate = now.getTime();
            now.set(Calendar.DATE, now.get(Calendar.DATE) - 1);
            Date startKeyDate = now.getTime();
            String startKeyDateStr = DateUtils.getYYYMMDD(startKeyDate);
            now.set(Calendar.DATE, now.get(Calendar.DATE) - day);
            String startTime = DateUtils.getYYYMMDD(startDate);
            Date endDate = now.getTime();
            String endTime = DateUtils.getYYYMMDD(endDate);
            List<RobotWarnMsgClassificationDTO> data = warnMsgMapper.getRobotWarnMsgByTime(startTime, endTime);

            String key = startKeyDateStr + CommonConstant.SYMBOL + endTime;
            map.put(key, data);
        }
        return map;
    }















}
