package com.zcxk.charge.xxl.jobs;

import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.zcxk.charge.api.dto.WorkOrderManageByAlarmDto;
import com.zcxk.charge.api.vo.AlarmDetailsEntityVo;
import com.zcxk.charge.api.vo.DeviceAlarmInfoForOrderVo;
import com.zcxk.charge.api.vo.DeviceCheckAlarmVo;
import com.zcxk.charge.core.dao.AlarmDetailMapper;
import com.zcxk.charge.core.entity.AlarmDetailsEntity;
import com.zcxk.charge.xxl.client.OperationManagerClient;
import com.zcxk.charge.xxl.client.UserCenterClient;
import com.zcxk.core.common.pojo.Message;
import com.zcxk.core.common.util.BeanCopyUtils;
import com.zcxk.core.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

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

/**
 * @description 验证设备离线状态
 * @author  Andy
 * @data 2021
 */
@Component
@Slf4j
public class CheckDeviceStateJob  extends BaseJob{

    @Resource
    private AlarmDetailMapper alarmDetailMapper;

    @Resource
    private OperationManagerClient operationManagerClient;

    @Resource
    private UserCenterClient userCenterClient;

    @XxlJob("checkDeviceStateJob")
    public ReturnT<String> execute(String string) {
        checkStateAlarm();
        return ReturnT.SUCCESS;
    }

    /**
    * 验证设备离线状态
    * @author Andy
    * @date 10:47 2021/8/18
    * @param :
    * @return void
    **/
    public void checkStateAlarm(){
        // 所有设备数据
        List<DeviceCheckAlarmVo> deviceCheckAlarmDtos = alarmDetailMapper.selectDeviceForCheckAlarm(null,"状态报警");
        // 根据设置筛选出离线设备
        List<DeviceCheckAlarmVo>  alarmlist = deviceCheckAlarmDtos.stream().filter(deviceCheckAlarmDto -> deviceCheckAlarmDto.checkdeviceOffLine()).collect(Collectors.toList());
        // 系统中已存在的离线报警
        List<AlarmDetailsEntityVo> alarmDetailsDtos = alarmDetailMapper.selectStateAlarm(null,"状态报警",null);
        // 已存在的报警信息转为map方便匹配
        Map<Integer,AlarmDetailsEntityVo> alarmDetailsDtoMap = alarmDetailsDtos.stream().collect(Collectors.toMap(AlarmDetailsEntityVo::getAlarmSettingId, a -> a,(k1, k2)->k1));
        // 需要新增的
        List<AlarmDetailsEntity>  deviceStateAlarmDtoNews = findInsertList(alarmlist, alarmDetailsDtoMap);
        if (deviceStateAlarmDtoNews.size() > 0) {
            alarmDetailMapper.batchInsert(deviceStateAlarmDtoNews);
        }
        // 需要更新的
        update(alarmlist, alarmDetailsDtoMap);
        if (alarmDetailsDtoMap.values().size() == 0) {
            return;
        }
        /**
         * 处理完成后，剩下的标记为历史数据
         * 循环更新历史报警数据
         * 系统时间
         */
        updateAlarmInfo(alarmDetailsDtoMap);
        // 恢复正常的设备id
        Set<Long> deviceIds = alarmDetailsDtoMap.values().stream().map(a -> a.getDeviceId().longValue()).collect(Collectors.toSet());
        // 获取恢复正常的设备工单
        List<WorkOrderManageByAlarmDto> workOrders = operationManagerClient.findWorkOrderByDeviceIds(new ArrayList<>(deviceIds));
        if (CollectionUtils.isEmpty(workOrders)) {
            return;
        }
        // 对报警信息分组
        Map<Integer,List<AlarmDetailsEntityVo>> deviceIdAlarmDetailsMap = regroup(alarmDetailsDtoMap);
        List<WorkOrderManageByAlarmDto> orderUpdate = new ArrayList<>();
        List<Long> orderDelete = new ArrayList<>();
        // 处理工单
        for (WorkOrderManageByAlarmDto orderManageByAlarmDto :workOrders){
            String taskDesc = orderManageByAlarmDto.getTaskDesc();
            List<AlarmDetailsEntityVo> alarmDetailsDtoList = deviceIdAlarmDetailsMap.get(orderManageByAlarmDto.getDeviceId().intValue());
            // 标记为历史数据 并 修改工单描述
            for (AlarmDetailsEntityVo alarmDetailsDto : alarmDetailsDtoList) {
                taskDesc = taskDesc.replace(";" + alarmDetailsDto.getAlarmContent(), "").replace(alarmDetailsDto.getAlarmContent(), "");
            }
            /**
             * if   工单未派单且无报警信息，删除工单
             * else 其他情况修改描述
             */
            if (isEmpty(taskDesc, orderManageByAlarmDto.getOrderStatus())) {
                orderDelete.add(orderManageByAlarmDto.getDeviceId());
            } else {
                orderManageByAlarmDto.setTaskDesc(taskDesc);
                orderUpdate.add(orderManageByAlarmDto);
            }
        }
        // 批量处理工单
        if (orderDelete.size() > 0) {
            operationManagerClient.batchDeleteByAlarms(orderDelete);
        }
        if (orderUpdate.size() > 0) {
            operationManagerClient.updateByAlarms(orderUpdate);
        }
    }

    private boolean isEmpty(String taskDesc, Integer orderStatus){
        return (orderStatus == null || orderStatus == 0) && StringUtils.isBlank(taskDesc);
    }

    /**
    * 更新报警信息
    * @author Andy
    * @date 11:01 2021/8/18
    * @param alarmDetailsDtoMap:
    * @return void
    **/
    private void updateAlarmInfo(Map<Integer,AlarmDetailsEntityVo> alarmDetailsDtoMap){
        Long currentTime = System.currentTimeMillis();
        for (AlarmDetailsEntityVo value : alarmDetailsDtoMap.values()){
            value.setDateUpdate(new Date());
            //从对象中拿到时间
            Long startTime = value.getAlarmStartTime().getTime();
            Long diff=(currentTime-startTime)/1000/60;
            value.setAlarmValue(diff.doubleValue());
            value.setAlarmEndTime(new Date());
            value.setState(0);
            AlarmDetailsEntity entity = new AlarmDetailsEntity();
            BeanCopyUtils.copyProperties(value, entity, AlarmDetailsEntity.class);
            // 直接更新
            alarmDetailMapper.update(entity);
        }
    }

    /**
    * 重新分组
    * @author Andy
    * @date 11:00 2021/8/18
    * @param alarmDetailsDtoMap:
    * @return java.util.Map<java.lang.Integer,java.util.List<com.zcxk.charge.api.vo.AlarmDetailsEntityVo>>
    **/
    private Map<Integer,List<AlarmDetailsEntityVo>> regroup( Map<Integer,AlarmDetailsEntityVo> alarmDetailsDtoMap){
        return alarmDetailsDtoMap.values().stream().collect(Collectors.groupingBy(AlarmDetailsEntityVo::getDeviceId));
    }


    /**
    * 更新数据
    * @author Andy
    * @date 10:55 2021/8/18
    * @param alarmlist:
    * @param alarmDetailsDtoMap:
    * @return void
    **/
    private void update(List<DeviceCheckAlarmVo>  alarmlist, Map<Integer,AlarmDetailsEntityVo> alarmDetailsDtoMap){
        alarmlist.stream().filter(deviceCheckAlarmDto -> alarmDetailsDtoMap.containsKey(deviceCheckAlarmDto.getAlarmSettingId())).map(d ->{
            AlarmDetailsEntityVo alarmDetailsDto = alarmDetailsDtoMap.get(d.getAlarmSettingId());
            alarmDetailsDto.setDateUpdate(new Date());
            alarmDetailsDto.setAlarmContent(d.getDeviceName()+"离线时间"+d.getAlarmCondition() +d.getAlarmValue()+"分钟");
            alarmDetailsDto.setAlarmValue(d.getDuration());
            AlarmDetailsEntity entity = new AlarmDetailsEntity();
            BeanCopyUtils.copyProperties(alarmDetailsDto, entity, AlarmDetailsEntity.class);
            alarmDetailMapper.update(entity);
            // 更新完成后从集合中移除，只剩下未处理的
            alarmDetailsDtoMap.remove(d.getAlarmSettingId());
            return entity;
        }).collect(Collectors.toList());
    }

    /**
    * 查找需要插入的数据
    * @author Andy
    * @date 10:54 2021/8/18
    * @param alarmlist:
    * @param alarmDetailsDtoMap:
    * @return java.util.List<com.zcxk.charge.core.entity.AlarmDetailsEntity>
    **/
    private List<AlarmDetailsEntity> findInsertList(List<DeviceCheckAlarmVo> alarmlist, Map<Integer,AlarmDetailsEntityVo> alarmDetailsDtoMap){
        return alarmlist.stream().filter(deviceCheckAlarmDto -> !alarmDetailsDtoMap.containsKey(deviceCheckAlarmDto.getAlarmSettingId())).map(d ->{
                    AlarmDetailsEntity alarmDetailsEntity = new AlarmDetailsEntity();
                    alarmDetailsEntity.setDateUpdate(new Date());
                    alarmDetailsEntity.setDateCreate(new Date());
                    alarmDetailsEntity.setStatus(1);
                    alarmDetailsEntity.setOpState(1);
                    alarmDetailsEntity.setState(1);
                    alarmDetailsEntity.setParentSceneId(d.getParentSceneId());
                    alarmDetailsEntity.setParentSceneName(d.getParentSceneName());
                    alarmDetailsEntity.setSceneId(d.getSceneId());
                    alarmDetailsEntity.setSceneName(d.getSceneName());
                    alarmDetailsEntity.setAlarmStartTime(new Date());
                    alarmDetailsEntity.setAlarmContent(d.getDeviceName()+"离线时间"+d.getAlarmCondition() +d.getAlarmValue()+"分钟");
                    alarmDetailsEntity.setAlarmValue(d.getDuration());
                    alarmDetailsEntity.setAttributeId(d.getAttributeId());
                    alarmDetailsEntity.setAlarmType("状态报警");
                    alarmDetailsEntity.setDeptOrgId(d.getDeptOrgId());
                    alarmDetailsEntity.setCompanyOrgId(d.getCompanyOrgId());
                    alarmDetailsEntity.setDeviceId(d.getDeviceId());
                    alarmDetailsEntity.setTenantId(d.getTenantId());
                    alarmDetailsEntity.setAlarmSettingId(d.getAlarmSettingId());
                    // 发送信息
                    sendMessage(d);
                    return alarmDetailsEntity;
                }).collect(Collectors.toList());
    }

    /**
    * 发送消息
    * @author Andy
    * @date 10:53 2021/8/18
    * @param alarmVo:
    * @return void
    **/
    private void sendMessage(DeviceCheckAlarmVo alarmVo){
        Message message=new Message();
        message.setStatus(1);
        message.setTenantId(alarmVo.getTenantId());
        message.setMessageId(UUID.randomUUID().toString());
        JSONObject jsonObject = new JSONObject();
        //${场景名称}${设备名称}${状态}${报警规则}【${数值单位}】tjj4
        jsonObject.put("场景名称",alarmVo.getSceneName());
        jsonObject.put("设备名称",alarmVo.getDeviceName());
        jsonObject.put("状态","离线");
        jsonObject.put("报警规则",alarmVo.getAlarmCondition() + alarmVo.getAlarmValue());
        jsonObject.put("数值单位","分钟");
        //消息内容，如果需要动态使用，配合模板使用{key:value}
        message.setMessageContent(jsonObject.toJSONString());
        //消息类型
        message.setMessageType(2);
        //模板id
        message.setMessageTemplateId(2);
        //渠道
        message.setChannel(0);
        Integer companyOrgId = alarmVo.getCompanyOrgId();
        Integer departmentOrgId = alarmVo.getDeptOrgId();
        List<Integer> taskUsers = userCenterClient.findUserIdsByPermissonOrg(alarmVo.getTenantId(),companyOrgId,departmentOrgId);
        try{
            if(taskUsers!=null){
                taskUsers.forEach(id->{
                    message.setUserId(id);
                    super.send(message);
                });
            }
        }catch(Exception e){
            e.printStackTrace();
            log.info("推送报警消息失败：{}",e.getMessage());
        }
    }


}
