import * as Hapi from "@hapi/hapi";
import * as http from "node:http";
import type { HttpTerminator } from "http-terminator";
import * as Glue from "@hapi/glue";
import * as Promster from "@promster/hapi";
import figlet from "figlet";
import PinoPlugin from "hapi-pino";
import { createServer as createPrometheusServer } from "@promster/server";
import { createHttpTerminator } from "http-terminator";

import { configureLogger } from "./logger.js";
import RequestIdPlugin from "./plugins/request-id.js";
import StatusPlugin from "./plugins/status.js";
import ConfigPlugin from "./plugins/config.js";
import { IMetamigoConfig } from "./config/index.js";

export interface Server {
  hapiServer: Hapi.Server;
  promServer?: http.Server;
  promTerminator?: HttpTerminator;
}
export const deployment = async <T extends IMetamigoConfig>(
  manifest: Glue.Manifest,
  config: T,
  start = false
): Promise<Server> => {
  const hapiServer: Hapi.Server = await Glue.compose(manifest);

  await hapiServer.initialize();

  if (!start) return { hapiServer };

  await announce(config);

  await hapiServer.start();

  const { port, address } = config.metrics;
  const promServer = await createPrometheusServer({
    port,
    hostname: address,
  });
  const promTerminator = createHttpTerminator({
    server: promServer,
  });

  console.log(`
🚀 Server  listening on http://${hapiServer.info.address}:${hapiServer.info.port}
   Metrics listening on http://${address}:${port}
`);

  return {
    hapiServer,
    promServer,
    promTerminator,
  };
};

export const stopDeployment = async (server: Server): Promise<void> => {
  await server.hapiServer.stop();
  if (server.promTerminator) await server.promTerminator.terminate();
};

export const defaultPlugins = <T extends IMetamigoConfig>(
  config: T
): string[] | Glue.PluginObject[] | Array<string | Glue.PluginObject> => {
  const {
    logRequestStart,
    logRequestComplete,
    logRequestPayload,
    logRequestQueryParams,
    level,
    redact,
    ignorePaths,
    ignoreTags,
    requestIdHeader,
  } = config.logging;
  const plugins = [
    { plugin: ConfigPlugin, options: { config } },
    {
      plugin: PinoPlugin,
      options: {
        level,
        instance: configureLogger(config),
        logRequestStart,
        logRequestComplete,
        logPayload: logRequestPayload,
        logQueryParams: logRequestQueryParams,
        redact: {
          paths: redact,
          remove: true,
        },
        ignorePaths,
        ignoreTags,
      },
    },
    {
      plugin: RequestIdPlugin,
      options: {
        header: requestIdHeader,
      },
    },
    { plugin: StatusPlugin },
    { plugin: Promster.createPlugin() },
  ];
  return plugins;
};

export const announce = async <T extends IMetamigoConfig>(
  config: T
): Promise<void> =>
  new Promise((resolve, reject) => {
    figlet.text(
      config.meta.name,
      { font: config.meta.figletFont as any },
      (err, text) => {
        if (err) reject(err);
        console.log(`${text}`);
        resolve();
      }
    );
  });
