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 = 10;

  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;
      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);
      }
      this.reconnect();
    };

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

  public disconnect(): void {
    if (this.socket) {
      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 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');
    }
  }
}