import { NextFunction, Request, RequestHandler, Response } from "express";

const registeredMiddlewares: Record<string, RequestHandler> = {};

function registerMiddleware(name: string, middleware: RequestHandler) {
  return (req: Request, res: Response, next: NextFunction) => {
    registeredMiddlewares[name] = middleware;
    next();
  };
}

function applyMiddleware(middlewares: string | Array<string>) {
  const middlewareNames = typeof middlewares === "string" ? [middlewares] : middlewares;

  return (req: Request, res: Response, next: NextFunction) => {
    middlewareNames.forEach((name) => {
      const middleware = registeredMiddlewares[name];
      if (middleware) {
        middleware(req, res, next);
      } else {
        next();
      }
    });
  };
}

function createMiddlewareMap() {
  return new Map<string, RequestHandler>();
}

function composeMiddleware(middlewareArray: any[]) {
  if (!middlewareArray.length) {
    return function (req: Request, res: Response, next: NextFunction) {
      next();
    };
  }

  const head = middlewareArray[0];
  const tail = middlewareArray.slice(1);

  return function (req: Request, res: Response, next: NextFunction) {
    head(req, res, function (err: unknown) {
      if (err) next(err);
      composeMiddleware(tail)(req, res, next);
    });
  };
}

export { applyMiddleware, composeMiddleware, createMiddlewareMap, registerMiddleware };
