export class WebSocketClient {
  [x: string]: any;
  private socket: WebSocket | null = null;
  private url: string;
  private protocols?: string | string[];
  private onMessageCallback?: (event: MessageEvent) => void;
  private onOpenCallback?: () => void;
  private onCloseCallback?: (event: CloseEvent) => void;
  private onErrorCallback?: (event: Event) => void;
  private reconnectInterval: number = 5000;
  private reconnectAttempts: number = 0;
  private maxReconnectAttempts: number = 5;
  private isDisconnected: boolean = false;

  constructor(url: string, protocols?: string | string[]) {
    this.url = url;
    this.protocols = protocols;
  }

  public connect(): void {
    console.log('WebSocket connecting...', this);

    this.socket = new WebSocket(this.url, this.protocols);

    this.socket.onopen = () => {
      console.log('WebSocket connected');
      this.reconnectAttempts = 0;
      this.isDisconnected = false;
      if (this.onOpenCallback) {
        this.onOpenCallback();
      }
    };

    this.socket.onmessage = (event: MessageEvent) => {
      if (this.onMessageCallback) {
        this.onMessageCallback(event);
      }
    };

    this.socket.onclose = (event: CloseEvent) => {
      console.log(
        `WebSocket closed with code ${event.code} and reason ${event.reason}`,
      );
      if (this.onCloseCallback) {
        this.onCloseCallback(event);
      }
      if (!this.isDisconnected) {
        this.reconnect();
      }
    };

    this.socket.onerror = (event: Event) => {
      console.error('WebSocket error:', event);
      if (this.onErrorCallback) {
        this.onErrorCallback(event);
      }
      if (!this.isDisconnected) {
        this.reconnect();
      }
    };
  }

  public disconnect(): void {
    if (this.socket) {
      this.isDisconnected = true;
      this.socket.close();
      console.log('WebSocket disconnected');
    }
  }

  public onOpen(callback: () => void): void {
    this.onOpenCallback = callback;
  }

  public onClose(callback: (event: CloseEvent) => void): void {
    this.onCloseCallback = callback;
  }

  public onError(callback: (event: Event) => void): void {
    this.onErrorCallback = callback;
  }

  public onMessage(callback: (event: MessageEvent) => void): void {
    this.onMessageCallback = callback;
  }

  // 心跳包
  public onHeartbeat(): void {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send('heartbeat');
    } else {
      console.error('WebSocket is not open');
    }
  }

  public send(message: string): void {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
    } else {
      console.error('WebSocket is not open');
    }
  }

  private reconnect(): void {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      console.log(
        `WebSocket reconnecting in ${this.reconnectInterval / 1000} seconds...`,
      );
      setTimeout(() => {
        this.connect();
        this.reconnectAttempts++;
      }, this.reconnectInterval);
    } else {
      console.error('WebSocket maximum reconnection attempts reached');
    }
  }
}
