import { Request, Response } from '@types/express';
import Transaction from './Transaction';

export default abstract class Handler {
  private _handlers: array<Function> = [];
  private _method_handlers: Record<string, Function> = {};

  protected register_handler (f: Function): void {
    this._handlers.push (f);
  }

  protected register_handler (method: string, f: Function): void {
    const m = method.toUpperCase ();
    if (typeof this._method_handlers[m] !== 'undefined')
      throw new Error (`Handler for ${m} already registered`);
    this._method_handlers[m] = f;
  }

  private async run_method_handler (method: string, t: Transaction): void {
    const m = method.toUpperCase ();
    if (this._method_handlers[m] !== 'undefined')
      await this._method_handlers[m] (t);
  }

  public async run_http_handler (req: Request, res: Response): void {
    const t = new Transaction (req, res);
    for (const handler of this._handlers) {
      // eslint-disable-next-line no-await-in-loop
      if (await handler (t) === false) {
        if (!t.status.has_status)
          t.status.error ();
        t.finalize ();
        return;
      }
    }
    await this.run_method_handler ('ALL', t);
    await this.run_method_handler (t.req.method, t);
  }

  public abstract get path(): string;
}