import { Prepare, TimeoutPrepare } from "../prepare";

export interface PingCommandParams {
  pingWaiting?: number;
  respPingWaiting?: number;
  sendPing?: () => void;
}

const defaultPingPongCommandParams: Required<PingCommandParams> = {
  pingWaiting: 6000,
  respPingWaiting: 10000,
  sendPing: () => {},
};
export class PingCommand {
  params: Required<PingCommandParams>;
  connection: any;
  cleanups: Array<() => void> = [];
  interval: ReturnType<typeof setInterval> | undefined;
  pingTimeoutTimer: ReturnType<typeof setTimeout> | undefined;
  pingPrepare: Prepare | undefined;
  reStartRecording?: () => {};
  isRequesting?: boolean;

  constructor(context: any, params: PingCommandParams = {}, reStartRecording: () => {}) {
    this.connection = context?.connection;
    this.params = Object.assign({}, defaultPingPongCommandParams, params);
    this.reStartRecording = reStartRecording;
    this.isRequesting = false;
  }
  onReady() {
    this.needCleanups(
      this.connection.on("open", () => {
        this.startPingPong();
      }),
      this.connection.on("close", () => {
        this.stopPingPong();
      })
    );
  }
  needCleanups(...cleanups: Array<() => void>) {
    this.cleanups = this.cleanups.concat(cleanups);
  }

  sendMessage() {
    this.params?.sendPing();
  }

  cleanup() {
    this.cleanups.forEach(cleanup => {
      cleanup();
    });
    this.cleanups = [];
  }

  onMessage(message: any) {
    const { output } = message?.payload || {};
    if (output?.action === "ping") {
      if (this.pingPrepare) {
        this.pingPrepare.resolve();
        this.pingPrepare = undefined;
      }
    }
  }

  async doPingPong() {
    try {
      if (this.pingPrepare) {
        this.pingPrepare.reject();
      }
      this.pingPrepare = new TimeoutPrepare(() => {}, this.params.respPingWaiting);
      console.log("发送。。。。");
      this.sendMessage();
      await this.pingPrepare.waiting;
      this.stopPingTimeout();

      // eslint-disable-next-line alidocs/catch-call-function
    } catch (error) {
      if (!this.pingTimeoutTimer) {
        if (this.connection.isConnected()) {
          this.pingTimeoutTimer = undefined;
          console.log("重新连接ping");
          await this.reStartRecording?.();
        }
      }
    }
  }

  startPingPong() {
    if (this.interval) {
      this.stopPingPong();
    }
    this.interval = setInterval(() => {
      this.doPingPong();
    }, this.params.pingWaiting);
  }

  stopPingPong() {
    if (!this.interval) {
      return;
    }
    clearInterval(this.interval);

    if (this.pingPrepare) {
      this.pingPrepare.resolve();
    }
    this.interval = undefined;
    this.pingPrepare = undefined;
    this.stopPingTimeout();
  }

  stopPingTimeout() {
    if (this.pingTimeoutTimer) {
      clearTimeout(this.pingTimeoutTimer);
      this.pingTimeoutTimer = undefined;
    }
  }
}
