// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import EventEmitter from 'node:events';

import {
  hasBuildExpired,
  getBuildExpirationTimestamp,
} from '../util/buildExpiration.std.ts';
import { LongTimeout } from '../util/timeout.std.ts';
import { createLogger } from '../logging/log.std.ts';
import { itemStorage } from '../textsecure/Storage.preload.ts';

const log = createLogger('buildExpiration');

export class BuildExpirationService extends EventEmitter {
  constructor() {
    super();

    // Let API users subscribe to `expired` event before firing it.
    queueMicrotask(() => this.#startTimer());
  }

  hasBuildExpired(): boolean {
    const autoDownloadUpdate = itemStorage.get('auto-download-update', true);

    return hasBuildExpired({
      buildExpirationTimestamp: this.#getBuildExpirationTimestamp(),
      autoDownloadUpdate,
      now: Date.now(),
      logger: log,
    });
  }

  // Private

  #getBuildExpirationTimestamp(): number {
    const autoDownloadUpdate = itemStorage.get('auto-download-update', true);

    return getBuildExpirationTimestamp({
      version: window.getVersion(),
      packagedBuildExpiration: window.getBuildExpiration(),
      remoteBuildExpiration: itemStorage.get('remoteBuildExpiration'),
      autoDownloadUpdate,
      logger: log,
    });
  }

  #startTimer(): void {
    const timestamp = this.#getBuildExpirationTimestamp();
    const now = Date.now();
    if (timestamp <= now) {
      if (this.hasBuildExpired()) {
        log.warn('expired');
        this.emit('expired');
      }
      return;
    }

    const delayMs = timestamp - now;
    log.info(`expires in ${delayMs}ms`);

    new LongTimeout(() => {
      if (this.hasBuildExpired()) {
        log.warn('expired');
        this.emit('expired');
      } else {
        this.#startTimer();
      }
    }, delayMs);
  }

  // EventEmitter types

  public override on(type: 'expired', callback: () => void): this;

  public override on(
    type: string | symbol,
    // oxlint-disable-next-line typescript/no-explicit-any
    listener: (...args: Array<any>) => void
  ): this {
    return super.on(type, listener);
  }

  public override emit(type: 'expired'): boolean;

  // oxlint-disable-next-line typescript/no-explicit-any
  public override emit(type: string | symbol, ...args: Array<any>): boolean {
    return super.emit(type, ...args);
  }
}
