import { addIDBData } from './database';
import { isEmpty } from 'lodash-es';

interface SSEMessage {
  module: string;
  data: any;
  [key: string]: any;
}

const BASE_URL = process.env.NODE_ENV === 'production' ? import.meta.env.VITE_APP_SERVER : '/api';

enum ConnectionState {
  CONNECTING = 0,
  OPEN = 1,
  CLOSED = 3, // SSE没有CLOSING状态
}

type Callback = (message: SSEMessage) => void;

/**
 * SSE 接收器
 */
export class Receiver {
  public static readonly instances: Map<string, Receiver> = new Map();

  /**
   * 获取单例
   * @param url 服务地址
   * @returns
   */
  static getInstance(url: string) {
    if (!this.instances.has(url)) {
      this.instances.set(url, new Receiver());
    }
    return this.instances.get(url)!;
  }

  private es: EventSource | null = null;
  private readonly onMessageCallbacks: Callback[] = [];
  private readonly onErrorCallbacks: Array<(error: Event) => void> = [];
  private connectionState: ConnectionState = ConnectionState.CLOSED;

  constructor() {
    this.connect();
  }

  /**
   * 监听消息
   * @param callback 监听消息的回调
   */
  onMessage(callback: (message: SSEMessage) => void) {
    this.onMessageCallbacks.push(callback);
  }

  /**
   * 监听错误
   * @param callback 监听错误的回调
   */
  onError(callback: (error: Event) => void) {
    this.onErrorCallbacks.push(callback);
  }

  /**
   * 关闭连接
   */
  close() {
    if (this.es) {
      this.es.close();
      this.es = null;
      this.connectionState = ConnectionState.CLOSED;
    }
  }

  /**
   * 获取连接状态
   */
  getConnectionState(): ConnectionState {
    return this.connectionState;
  }

  /**
   * 连接SSE
   */
  private connect() {
    this.connectionState = ConnectionState.CONNECTING;
    this.es = new EventSource(BASE_URL + '/sse/subscribe?key=Journey_Touch_PointSWAD');

    this.es.addEventListener('open', () => {
      this.connectionState = ConnectionState.OPEN;
    });

    this.es.addEventListener('message', async (event) => {
      try {
        const message: SSEMessage = JSON.parse(event.data);
        if (!isEmpty(message)) {
          await addIDBData(message.module, message.data);
          this.onMessageCallbacks.forEach((callback) => callback(message));
        }
      } catch (error) {
        this.onErrorCallbacks.forEach((callback) => callback(error as Event));
      }
    });

    this.es.addEventListener('error', (error) => {
      this.onErrorCallbacks.forEach((callback) => callback(error));
      // 关闭连接
      this.close();

      setTimeout(() => {
        this.connect();
      }, 10000);
    });

    // 关闭页面时断开连接
    window.addEventListener('beforeunload', () => {
      this.close();
    });
  }
}
