export class DebouncePublisher<T> {
  private last_event_time = Date.now();
  private unpublished_data: T | undefined;
  private interval_id: number | undefined;

  constructor(
    private readonly publisher: (data: T) => void | Promise<void>,
    private readonly debounce_ms = 100,
  ) {}

  public start() {
    if (typeof this.interval_id !== "undefined") {
      return;
    }
    this.interval_id = setInterval(
      () => this.debounce_publish(),
      this.debounce_ms,
    );
  }

  public stop() {
    if (this.interval_id === null) {
      return;
    }
    clearInterval(this.interval_id);
    delete this.interval_id;
  }

  public update(data: T) {
    this.unpublished_data = data;
    this.debounce_publish();
  }

  private debounce_publish() {
    if (
      Date.now() - this.last_event_time < this.debounce_ms ||
      typeof this.unpublished_data === "undefined"
    ) {
      return;
    }

    this.last_event_time = Date.now();
    this.publisher(this.unpublished_data);
    this.unpublished_data = undefined;
  }
}