import * as plugins from './classes.plugins.js';

import { InterestMap, type IInterestComparisonFunc } from './classes.interestmap.js';

export interface IInterestOptions<DTInterestFullfillment> {
  markLostAfterDefault: number;
  defaultFullfillment?: DTInterestFullfillment;
}

export class Interest<DTInterestId, DTInterestFullfillment> {
  public options: IInterestOptions<DTInterestFullfillment>;

  private interestMapRef: InterestMap<DTInterestId, DTInterestFullfillment>;
  public originalInterest: DTInterestId;
  public comparisonFunc: IInterestComparisonFunc<DTInterestId>;
  public destructionTimer = new plugins.smarttime.Timer(10000);
  public isFullfilled = false;
  private isDestroyed = false;

  /**
   * a generic store to store objects in that are needed for fullfillment;
   */
  public fullfillmentStore: any[] = [];

  /**
   * a cancellable timeout for the markLostAfterDefault feature
   */
  private markLostTimeout: InstanceType<typeof plugins.smartdelay.Timeout> | null = null;

  /**
   * quick access to a string that makes the interest comparable for checking for similar interests
   */
  public get comparisonString() {
    return this.comparisonFunc(this.originalInterest);
  }

  private interestDeferred: plugins.smartpromise.Deferred<DTInterestFullfillment> =
    new plugins.smartpromise.Deferred();
  public interestFullfilled = this.interestDeferred.promise;

  /**
   * fullfill the interest
   */
  public fullfillInterest(objectArg: DTInterestFullfillment) {
    this.isFullfilled = true;
    this.fullfillmentStore = [];
    this.interestDeferred.resolve(objectArg);
    this.destroy();
  }

  constructor(
    interestMapArg: InterestMap<DTInterestId, DTInterestFullfillment>,
    interestArg: DTInterestId,
    comparisonFuncArg: IInterestComparisonFunc<DTInterestId>,
    optionsArg?: IInterestOptions<DTInterestFullfillment>
  ) {
    this.interestMapRef = interestMapArg;
    this.originalInterest = interestArg;
    this.comparisonFunc = comparisonFuncArg;
    this.options = optionsArg;

    this.destructionTimer.completed.then(() => {
      if (!this.isDestroyed) {
        this.destroy();
      }
    });
    if (this.options?.markLostAfterDefault) {
      this.markLostTimeout = new plugins.smartdelay.Timeout(this.options.markLostAfterDefault);
      this.markLostTimeout.promise.then(() => {
        if (!this.isDestroyed) {
          this.markLost();
        }
      });
    }
  }

  // ===============================
  // LIFECYCLE MANAGEMENT
  // ===============================

  /**
   * self destructs the interest
   */
  public destroy() {
    if (this.isDestroyed) {
      return;
    }
    this.isDestroyed = true;

    // Cancel timers to release references
    this.destructionTimer.reset();
    if (this.markLostTimeout) {
      this.markLostTimeout.cancel();
      this.markLostTimeout = null;
    }

    // Clear the fulfillment store
    this.fullfillmentStore = [];

    // Remove from the InterestMap
    this.interestMapRef.removeInterest(this);

    // Fulfill with default if not yet fulfilled (inlined to avoid mutual recursion)
    if (!this.isFullfilled && this.options?.defaultFullfillment) {
      this.isFullfilled = true;
      this.interestDeferred.resolve(this.options.defaultFullfillment);
    }
  }

  /**
   * notifies the interest that the interest in it has been lost
   */
  public markLost() {
    this.destructionTimer.start();
  }

  /**
   * notifies the interest that the interest in it has been restored
   */
  public renew() {
    this.destructionTimer.reset();
  }
}
