import { Server } from '../../server';
import { HttpHandler, Middleware } from '../http';
import { Guid } from '../util';

abstract class Registry {
	private static httpHandlers: {[key: string]: HttpHandler} = {};
	private server: Server | null = null;

	protected abstract registerRoutes(): Promise<Registry>;
	protected abstract registerMiddlewares(): Promise<Registry>;

	public async registerHttpHandlers(): Promise<Registry> {
		await this.registerRoutes();
		await this.registerMiddlewares();
		return this;
	}

	protected registerHttpHandler(handler: HttpHandler): Registry {
		let id = Guid.new();
		while(Registry.httpHandlers[id] != null)
			id = Guid.new();
		
		Registry.httpHandlers[id] = handler;

		return this;
	}

	public setServer(server: Server): Registry {
		if(this.server != null)
			return this;
		return this.server = server, this;
	}

	public getServer(): Server | null {
		return this.server;
	}

	public static getHttpHandlers(): HttpHandler[] {
		const handlers: HttpHandler[] = [];
		const middlewareOrders: number[] = [];
		for(const key in Registry.httpHandlers) {
			const handler = Registry.httpHandlers[key];
			if(handler instanceof Middleware) {
				const order = handler.getOrder();
				if(middlewareOrders.includes(order))
					throw `Invalid middleware order number: ${handler.constructor.name}`;
				middlewareOrders.push(order);
			}
			handlers.push(Registry.httpHandlers[key]);
		}

		return handlers.sort((a, b) => a instanceof Middleware && b instanceof Middleware && (a.getOrder() - b.getOrder()) || (a instanceof Middleware && -1 || (b instanceof Middleware && 1 || 0)));
	}
}

export default Registry;