package com.zcxk.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zcxk.client.OperationManagerClient;
import com.zcxk.client.UserCenterClient;
import com.zcxk.dao.AlarmDetailMapper;
import com.zcxk.dto.*;
import com.zcxk.entity.AlarmDetailsEntity;
import com.zcxk.entity.Message;
import com.zcxk.model.LoginUser;
import com.zcxk.service.AlarmDetailsService;
import com.zcxk.util.DatesUtil;
import com.zcxk.util.UserUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

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

/**
 * @description
 * @auto wangli
 * @data 2020-11-17 15:48
 */
@Service
@Log4j2
public class AlarmDetailsServiceImpl implements AlarmDetailsService {

    @Resource
    private AlarmDetailMapper alarmDetailMapper;
    @Autowired
    private OperationManagerClient operationManagerClient;
    @Autowired
    private UserCenterClient userCenterClient;

    @Resource(name = "messageRabbitTemplate")
    private AmqpTemplate messageRabbitTemplate;

    @Value("${receive.exchange.name}")
    private  String receiveExchangeName;
    @Value("${dispath.routing.key}")
    private  String dispathRoutingKey;


    private void send(Message message){
        log.debug("消息发送 exchange={}  routingkey={} 用户id={}",receiveExchangeName,dispathRoutingKey,message.getUserId());
        messageRabbitTemplate.convertAndSend(receiveExchangeName,dispathRoutingKey, JSONObject.toJSONString(message));
    }

    @Override
    public AlarmDetailsDto selectById(Integer id) {
        return alarmDetailMapper.selectById(id);
    }

    @Override
    public List<AlarmDetailsDto> selectByDeviceId(Long sceneId,Integer deviceId) {
        return alarmDetailMapper.selectByDeviceId(sceneId,deviceId);
    }
    @Override
    public List<AlarmDetailsDto> selectByDeviceAttributeId(Long sceneId,Integer deviceId,Integer attributeId) {
        return alarmDetailMapper.selectByDeviceAttributeId(sceneId, deviceId,attributeId);
    }

    @Override
    public List<AlarmDetailsDto> selectBySceneId(Integer sceneId) {
        return alarmDetailMapper.selectBySceneId(sceneId);
    }

    @Override
    public List<AlarmDetailsRealTimeDto> selectRealTimeByIds(List<Integer> ids) {
        return alarmDetailMapper.selectRealTimeByIds(ids);
    }
    @Override
    public List<AlarmDetailsHistoryDto> selectHistoryByIds(List<Integer> ids) {
        return alarmDetailMapper.selectHistoryByIds(ids);
    }
    @Override
    public Integer insert(AlarmDetailsEntity alarmDetailsEntity) {
        return alarmDetailMapper.insert(alarmDetailsEntity);
    }

    @Override
    public Integer batchInsert(List<AlarmDetailsEntity> alarmDetails) {
        return alarmDetailMapper.batchInsert(alarmDetails);
    }

    @Override
    public Integer deleteById(Integer id) {
        return alarmDetailMapper.deleteById(id);
    }

    @Override
    public Integer batchDelete(List<Integer> ids) {

        return alarmDetailMapper.batchDelete(ids);
    }

    @Override
    public Integer suspendedById(Integer id , Integer opState) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        return alarmDetailMapper.suspendedById(id,opState,new Date(),loginUser.getUsername());
    }

    @Override
    public Integer update(AlarmDetailsEntity alarmDetailsEntity) {
        return alarmDetailMapper.update(alarmDetailsEntity);
    }

    @Override
    public List<AlarmDetailsDto> selectList(AlarmDetailsDto alarmDetailsDto) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        alarmDetailsDto.setTenantId(loginUser.getTenantId());
        alarmDetailsDto.setProgramItems(loginUser.getProgramItemList());
        alarmDetailsDto.setUserType(loginUser.getType());
        //1是公司，2是公司及以下，3部门，4部门及以下，5自定义
        alarmDetailsDto.setPermissonType(loginUser.getPermissonType());
        return alarmDetailMapper.selectList(alarmDetailsDto);
    }

    @Override
    public IPage<AlarmDetailsDto> selectPage(IPage<AlarmDetailsDto> page, AlarmDetailsDto alarmDetailsDto) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        alarmDetailsDto.setTenantId(loginUser.getTenantId());
        alarmDetailsDto.setProgramItems(loginUser.getProgramItemList());
        alarmDetailsDto.setUserType(loginUser.getType());
        //1是公司，2是公司及以下，3部门，4部门及以下，5自定义
        alarmDetailsDto.setPermissonType(loginUser.getPermissonType());
        return alarmDetailMapper.selectPage(page,alarmDetailsDto);
    }

    @Override
    public List<AlarmDetailsRealTimeDto> selectRealTimeList(AlarmDetailsDto alarmDetailsDto) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        alarmDetailsDto.setTenantId(loginUser.getTenantId());
        alarmDetailsDto.setProgramItems(loginUser.getProgramItemList());
        alarmDetailsDto.setUserType(loginUser.getType());
        //1是公司，2是公司及以下，3部门，4部门及以下，5自定义
        alarmDetailsDto.setPermissonType(loginUser.getPermissonType());
        return alarmDetailMapper.selectRealTimeList(alarmDetailsDto);
    }

    @Override
    public IPage<AlarmDetailsRealTimeDto> selectRealTimePage(IPage<AlarmDetailsRealTimeDto> page, AlarmDetailsDto alarmDetailsDto) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        alarmDetailsDto.setTenantId(loginUser.getTenantId());
        alarmDetailsDto.setProgramItems(loginUser.getProgramItemList());
        alarmDetailsDto.setUserType(loginUser.getType());
        //1是公司，2是公司及以下，3部门，4部门及以下，5自定义
        alarmDetailsDto.setPermissonType(loginUser.getPermissonType());
        return alarmDetailMapper.selectRealTimePage(page,alarmDetailsDto);
    }

    @Override
    public List<AlarmDetailsHistoryDto> selectHistoryList(AlarmDetailsDto alarmDetailsDto) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        alarmDetailsDto.setTenantId(loginUser.getTenantId());
        alarmDetailsDto.setProgramItems(loginUser.getProgramItemList());
        alarmDetailsDto.setUserType(loginUser.getType());
        //1是公司，2是公司及以下，3部门，4部门及以下，5自定义
        alarmDetailsDto.setPermissonType(loginUser.getPermissonType());
        return alarmDetailMapper.selectHistoryList(alarmDetailsDto);
    }

    @Override
    public IPage<AlarmDetailsHistoryDto> selectHistoryPage(IPage<AlarmDetailsHistoryDto> page, AlarmDetailsDto alarmDetailsDto) {
        LoginUser loginUser = UserUtil.getCurrentUser();
        alarmDetailsDto.setTenantId(loginUser.getTenantId());
        alarmDetailsDto.setProgramItems(loginUser.getProgramItemList());
        alarmDetailsDto.setUserType(loginUser.getType());
        //1是公司，2是公司及以下，3部门，4部门及以下，5自定义
        alarmDetailsDto.setPermissonType(loginUser.getPermissonType());
        return alarmDetailMapper.selectHistoryPage(page,alarmDetailsDto);
    }


    public void checkStateAlarm(){
        //所有设备数据
        List<DeviceCheckAlarmDto> deviceCheckAlarmDtos = alarmDetailMapper.selectDeviceForCheckAlarm(null,"状态报警");
        //根据设置筛选出离线设备
        List<DeviceCheckAlarmDto>  alarmlist = deviceCheckAlarmDtos.stream().filter(deviceCheckAlarmDto -> deviceCheckAlarmDto.checkdeviceOffLine()).collect(Collectors.toList());
        //系统中已存在的离线报警
        List<AlarmDetailsDto> alarmDetailsDtos = alarmDetailMapper.selectStateAlarm(null,"状态报警",null);
        //已存在的报警信息转为map方便匹配
        Map<Integer,AlarmDetailsDto> alarmDetailsDtoMap = alarmDetailsDtos.stream().collect(Collectors.toMap(AlarmDetailsDto::getAlarmSettingId, a -> a,(k1, k2)->k1));
        //需要新增的
        List<AlarmDetailsEntity>  deviceStateAlarmDtoNews =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());

                    Message message=new Message();
                    message.setStatus(1);
                    message.setTenantId(d.getTenantId());
                    message.setMessageId(UUID.randomUUID().toString());
                    JSONObject jsonObject = new JSONObject();
                    //${场景名称}${设备名称}${状态}${报警规则}【${数值单位}】
                    jsonObject.put("场景名称",d.getSceneName());
                    jsonObject.put("设备名称",d.getDeviceName());
                    jsonObject.put("状态","离线");
                    jsonObject.put("报警规则",d.getAlarmCondition() +d.getAlarmValue());
                    jsonObject.put("数值单位","分钟");
                    message.setMessageContent(jsonObject.toJSONString());  //消息内容，如果需要动态使用，配合模板使用{key:value}
                    message.setMessageType(2); //消息类型
                    message.setMessageTemplateId(2);   //模板id
                    message.setChannel(0);   //渠道
                    Integer companyOrgId = d.getCompanyOrgId();
                    Integer departmentOrgId = d.getDeptOrgId();
                    List<Integer> taskUsers = userCenterClient.findUserIdsByPermissonOrg(d.getTenantId(),companyOrgId,departmentOrgId);
                    try{
                        if(taskUsers!=null){
                            taskUsers.forEach(id->{
                                message.setUserId(id);
                                this.send(message);
                            });
                        }
                    }catch(Exception e){
                        e.printStackTrace();
                        log.info("推送报警消息失败：{}",e.getMessage());
                    }
                    return alarmDetailsEntity;
                })
                .collect(Collectors.toList());
        if(deviceStateAlarmDtoNews.size()>0){
            alarmDetailMapper.batchInsert(deviceStateAlarmDtoNews);
        }

        //需要更新的
        List<AlarmDetailsEntity>  deviceStateAlarmDtoOlds =alarmlist.stream()
                .filter(deviceCheckAlarmDto -> alarmDetailsDtoMap.containsKey(deviceCheckAlarmDto.getAlarmSettingId()))
                .map(d ->{
                    AlarmDetailsDto alarmDetailsDto = alarmDetailsDtoMap.get(d.getAlarmSettingId());
                    alarmDetailsDto.setDateUpdate(new Date());
                    alarmDetailsDto.setAlarmContent(d.getDeviceName()+"离线时间"+d.getAlarmCondition() +d.getAlarmValue()+"分钟");
                    alarmDetailsDto.setAlarmValue(d.getDuration());
                    alarmDetailMapper.update(alarmDetailsDto);//直接更新
                    alarmDetailsDtoMap.remove(d.getAlarmSettingId());//更新完成后从集合中移除，只剩下未处理的
                    return alarmDetailsDto;
                })
                .collect(Collectors.toList());


        //处理完成后，剩下的标记为历史数据
        if(alarmDetailsDtoMap.values().size() > 0) {
            //循环更新历史报警数据
            Long currentTime =System.currentTimeMillis(); //系统时间
            for(AlarmDetailsDto 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);
                alarmDetailMapper.update(value);//直接更新
            }

            //恢复正常的设备id
            Set<Long> deviceIds = alarmDetailsDtoMap.values().stream()
                    .map(a -> a.getDeviceId().longValue())
                    .collect(Collectors.toSet());
            //获取恢复正常的设备工单
            List<WorkOrderManageByAlarmDto> workOrders = operationManagerClient.findWorkOrderByDeviceIds(new ArrayList<>(deviceIds));
            //对报警信息分组
            Map<Integer,List<AlarmDetailsDto>> deviceIdAlarmDetailsMap = alarmDetailsDtoMap.values().stream().collect(Collectors.groupingBy(AlarmDetailsDto::getDeviceId));
            if (workOrders.size() > 0) {
                List<WorkOrderManageByAlarmDto> orderUpdate = new ArrayList<>();
                List<Long> orderDelete = new ArrayList<>();

                //处理工单
                for(WorkOrderManageByAlarmDto orderManageByAlarmDto :workOrders){
                    String taskDesc = orderManageByAlarmDto.getTaskDesc();
                    List<AlarmDetailsDto> alarmDetailsDtoList = deviceIdAlarmDetailsMap.get(orderManageByAlarmDto.getDeviceId().intValue());
                    //标记为历史数据 并 修改工单描述
                    for (AlarmDetailsDto alarmDetailsDto : alarmDetailsDtoList) {
                        /*alarmDetailsDto.setDateUpdate(new Date());
                        //从对象中拿到时间
                        Long startTime = alarmDetailsDto.getAlarmStartTime().getTime();
                        Long diff=(currentTime-startTime)/1000/60;
                        alarmDetailsDto.setAlarmValue(diff.doubleValue());
                        alarmDetailsDto.setAlarmEndTime(new Date());
                        alarmDetailsDto.setState(0);
                        alarmDetailMapper.update(alarmDetailsDto);//直接更新*/
                        taskDesc = taskDesc.replace(";" + alarmDetailsDto.getAlarmContent(), "")
                                .replace(alarmDetailsDto.getAlarmContent(), "");
                    }
                    if (orderManageByAlarmDto != null
                            && (orderManageByAlarmDto.getOrderStatus() == null || orderManageByAlarmDto.getOrderStatus() == 0)
                            && StringUtils.isBlank(taskDesc)) {
                        //工单未派单且无报警信息，删除工单
                        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);
                }

            }
        }
    }

   public void saveWorkOrderManageInfo(){
       List<DeviceAlarmInfoForOrder> deviceAlarmInfoForOrders = alarmDetailMapper.getAlarmInfoForWorkOrderManage();
       if(deviceAlarmInfoForOrders.size()>0){

           //获取已经存在的设备工单
           Set<Long> deviceIdSet = deviceAlarmInfoForOrders.stream().map(DeviceAlarmInfoForOrder::getDeviceId).collect(Collectors.toSet());
           List<WorkOrderManageByAlarmDto> workOrders = operationManagerClient.findWorkOrderByDeviceIds(new ArrayList<>(deviceIdSet));
           Map<Long,WorkOrderManageByAlarmDto> workOrderMap = workOrders.stream().collect(Collectors.toMap(WorkOrderManageByAlarmDto::getDeviceId, Function.identity(), (key1, key2) -> key2));

           List<WorkOrderManageByAlarmDto> workOrderManageByAlarms = new ArrayList<>();
           List<WorkOrderManageByAlarmDto> updates = new ArrayList<>();
           List<DeviceAlarmInfoForOrder> errData= new ArrayList<>();

           //组合工单，并发送消息
           for(DeviceAlarmInfoForOrder deviceAlarmInfoForOrder : deviceAlarmInfoForOrders){
               if(workOrderMap.containsKey(deviceAlarmInfoForOrder.getDeviceId()) && workOrderMap.get(deviceAlarmInfoForOrder.getDeviceId()) != null){
                   WorkOrderManageByAlarmDto orderManageByAlarmDto = workOrderMap.get(deviceAlarmInfoForOrder.getDeviceId());
                   orderManageByAlarmDto.setTaskDesc(orderManageByAlarmDto.getTaskDesc()+";"+deviceAlarmInfoForOrder.getTaskDesc());
                   updates.add(orderManageByAlarmDto);
                   continue;
               }
               WorkOrderManageByAlarmDto workOrderManageByAlarm = new WorkOrderManageByAlarmDto();
               workOrderManageByAlarm.setTaskNo(DatesUtil.formatDate(new Date(),"yyyyMMddHHmmssSSS")+((int) (Math.random()*(9999-1000)+1000)));
               workOrderManageByAlarm.setTenantId(deviceAlarmInfoForOrder.getTenantId());
               workOrderManageByAlarm.setParentSceneId(deviceAlarmInfoForOrder.getParentSceneId());
               workOrderManageByAlarm.setParentSceneName(deviceAlarmInfoForOrder.getParentSceneName());
               workOrderManageByAlarm.setDeviceId(deviceAlarmInfoForOrder.getDeviceId());
               workOrderManageByAlarm.setDeviceName(deviceAlarmInfoForOrder.getDeviceName());
               workOrderManageByAlarm.setCompanyOrgId(deviceAlarmInfoForOrder.getCompanyOrgId());
               workOrderManageByAlarm.setDepartmentOrgId(deviceAlarmInfoForOrder.getDepartmentOrgId());
               workOrderManageByAlarm.setAddress(deviceAlarmInfoForOrder.getAddress());
               workOrderManageByAlarm.setGeo(deviceAlarmInfoForOrder.getGeo());
               workOrderManageByAlarm.setOrderTime(deviceAlarmInfoForOrder.getOrderTime());
               workOrderManageByAlarm.setTaskDesc(deviceAlarmInfoForOrder.getTaskDesc());


               Message message=new Message();
               message.setStatus(1);
               message.setTenantId(deviceAlarmInfoForOrder.getTenantId());
               message.setMessageId(UUID.randomUUID().toString());
               JSONObject jsonObject = new JSONObject();
               jsonObject.put("工单类型"," ");
               jsonObject.put("工单编号",workOrderManageByAlarm.getTaskNo());
               message.setMessageContent(jsonObject.toJSONString());  //消息内容，如果需要动态使用，配合模板使用{key:value}
               message.setMessageType(7); //消息类型
               message.setMessageTemplateId(7);   //模板id
               message.setChannel(0);   //渠道
               Integer companyOrgId = null;
               Integer departmentOrgId = null;
               if(StringUtils.isNotBlank(workOrderManageByAlarm.getCompanyOrgId())){
                   companyOrgId=Integer.valueOf(workOrderManageByAlarm.getCompanyOrgId());
               }
               if(StringUtils.isNotBlank(workOrderManageByAlarm.getDepartmentOrgId())){
                   departmentOrgId=Integer.valueOf(workOrderManageByAlarm.getDepartmentOrgId());
               }
               try{
                   List<Integer> taskUsers = userCenterClient.findUserIdsByPermissonOrg(workOrderManageByAlarm.getTenantId(),companyOrgId,departmentOrgId);
                   if(taskUsers!=null){
                       taskUsers.forEach(id->{
                           message.setUserId(id);
                           this.send(message);
                       });
                   }
                   workOrderManageByAlarms.add(workOrderManageByAlarm);
               }catch (Exception e){
                   e.printStackTrace();
                   errData.add(deviceAlarmInfoForOrder);
               }
           }
           //去掉推送失败的数据
           if(errData.size()>0){
               deviceAlarmInfoForOrders.removeAll(errData);
           }
           //保存工单
           if(workOrderManageByAlarms.size()>0){
                operationManagerClient.saveByAlarms(workOrderManageByAlarms);
           }
           if(updates.size()>0){
                operationManagerClient.updateByAlarms(updates);
           }
           if(deviceAlarmInfoForOrders.size()>0){
               //标记报警已生成工单
               alarmDetailMapper.updateAlarmSendMessageState(deviceAlarmInfoForOrders);
           }
       }
   }


}
