import { EventEmitter } from "./emitter";
export class Response {
  _promise;
  _eventEmitter;
  _context;
  _elasped = null;
  _simplify;
  constructor(context, promise, simplify) {
    this._context = context;
    this._eventEmitter = new EventEmitter();
    this._simplify = simplify;
    this._promise = promise.then(
      (value) => {
        this._elasped ||= this._context.elapsedTime;
        this._eventEmitter.emit("complete", value);
        this._eventEmitter.clear();
        this._context.clear();
        return value;
      },
      (reason) => {
        this._elasped ||= this._context.elapsedTime;
        this._eventEmitter.emit("error", reason);
        this._eventEmitter.clear();
        this._context.clear();
        throw reason;
      }
    );
    this._context.on("update", (usage) => {
      this._eventEmitter.emit("progress", usage);
    });
  }
  // Event emitter methods
  on(type, listener) {
    this._eventEmitter.on(type, listener);
    return this;
  }
  off(type, listener) {
    this._eventEmitter.off(type, listener);
    return this;
  }
  once(type, listener) {
    this._eventEmitter.once(type, listener);
    return this;
  }
  bindSignal(signal) {
    if (signal.aborted) {
      this.abort(signal.reason);
    }
    const signalAbort = () => {
      this.abort(signal.reason);
    };
    signal.addEventListener("abort", () => signalAbort());
    void this.once("complete", () => signal.removeEventListener("abort", signalAbort));
    void this.once("error", () => signal.removeEventListener("abort", signalAbort));
    return this;
  }
  abort(reason) {
    this._context.controller.abort(reason);
  }
  // oxlint-disable-next-line no-thenable
  then(onfulfilled, onrejected) {
    return this._promise.then(
      (value) => {
        const simplified = this._simplify(value);
        return onfulfilled ? onfulfilled(simplified) : simplified;
      },
      (reason) => {
        if (onrejected) {
          return onrejected(reason);
        }
        throw reason;
      }
    );
  }
  catch(onrejected) {
    return this._promise.catch(onrejected);
  }
  async result() {
    const output = await this._promise;
    const usage = this._context.usage;
    return { output, usage, elapsed: this._elasped };
  }
}
