package com.ruoyi.common.sse;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import org.springframework.http.MediaType;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;

public abstract class SseApiSupport<T> {
  protected final List<SseEmitter<T>> emitters = new CopyOnWriteArrayList<>();

  /**
   * 订阅某种类型的消息
   *
   * @param timeout 会话超时
   * @param type    消息类型
   * @return
   */
  protected final SseEmitter<T> handleSubscribe(long timeout, T type) {
    SseEmitter<T> emitter = new SseEmitter(timeout, type);
    emitters.add(emitter);
    emitter.onTimeout(() -> {
      emitters.remove(emitter);
    });
    emitter.onCompletion(() -> {
      emitters.remove(emitter);
    });
    emitter.onError(e -> {
      emitters.remove(emitter);
    });
    return emitter;
  }

  /**
   * 订阅某种类型的消息
   * 超时：Long.MAX_VALUE
   *
   * @param type 消息类型
   * @return
   */
  protected final SseEmitter<T> handleSubscribe(T type) {
    return handleSubscribe(Long.MAX_VALUE, type);
  }

  /**
   * 根据条件发送action消息
   * @param predicate 条件为真发送
   * @param action action消息
   */
  public final void send(Predicate<SseEmitter<T>> predicate, SseAction<?> action) {
    List<SseEmitter<T>> removes = ListUtil.list(true);
    for (SseEmitter<T> e : emitters) {
      if (predicate.test(e)) {
        try {
          e.send(action, MediaType.APPLICATION_JSON);
        } catch (Exception e1) {
          removes.add(e);
        }
      }
    }
    emitters.removeAll(removes);
  }

  /**
   * 根据条件发送action消息
   * @param predicate 条件为真发送
   * @param action  action字符串
   * @param data 具体内容
   */
  public final void send(Predicate<SseEmitter<T>> predicate, String action, Object data) {
    send(predicate, SseAction.builder().action(action).data(data).build());
  }

  /**
   * 发送某种类型的action消息
   *
   * @param type   消息类型
   * @param action action消息
   */
  public final void send(T type, SseAction<?> action) {
    send(e -> ObjUtil.isNull(type) || ObjUtil.isNull(e.getType()) || ObjUtil.equals(type, e.getType()), action);

  }

  /**
   * 发送某种类型的action消息
   *
   * @param type
   * @param action
   * @param data
   */
  public final void send(T type, String action, Object data) {
    send(type, SseAction.builder().action(action).data(data).build());
  }

  /**
   * 发送某种类型的action=null的消息
   *
   * @param type
   * @param data
   */
  public final void send(T type, Object data) {
    send(type, SseAction.builder().data(data).build());
  }

  /**
   * 发送null类型(广播)的action消息
   *
   * @param action
   */
  public final void sendAll(SseAction<?> action) {
    send((T)null, action);
  }


  /**
   * 发送null类型(广播)的action消息
   *
   * @param action
   * @param data
   */
  public final void sendAll(String action, Object data) {
    sendAll(SseAction.builder().action(action).data(data).build());
  }

  /**
   * 发送null类型(广播)的action=null的消息
   *
   * @param data
   */
  public final void sendAll(Object data) {
    sendAll(SseAction.builder().data(data).build());
  }
}
