/* eslint-disable no-use-before-define */
import rTracer from "cls-rtracer";
import http from "http";
import { assign } from "lodash";
import { DateTime, Settings } from "luxon";

import { createSequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
import { trace } from "console";
import { config } from "../../config";
import { app } from "../express/app";
import { initLogger } from "../logger";
import { initStructure, insertUsers } from "../sequelize";

process.env.TZ = "UTC";
Settings.defaultLocale = "es-ES";
Settings.defaultZone = "utc";

const logger = initLogger(rTracer);

export const currentState = assign(
  {
    launchedAt: DateTime.now(),
    appPath: process.cwd(),
    //host: process.env.HOST || process.env.HOSTNAME || 'localhost',
    //port: process.env.PORT || 18888,
    environment: config.environment,
    connections: {},
  },
  config
);

const serverStop = (server: http.Server) => {
  const forceTimeout = 30000;

  return new Promise<void>((resolve, reject) => {
    logger.warn("⚡️ Shutting down server");

    setTimeout(() => {
      logger.error("Could not close connections in time, forcefully shutting down");
      resolve();
    }, forceTimeout).unref();

    server.close((err) => {
      if (err) {
        return reject(err);
      }

      logger.info("Closed out remaining connections.");
      logger.info("Bye!");
      resolve();
    });
  });

  /*const now = DateTime.now();
	// Destroy server and available connections.
	logger.info(`Time: ${now.toLocaleString()}`);
	logger.info('Shutting down at: ' + new Date());
	if (server) {
		server.close();
	}

	logger.info('Bye!');
	process.exit(1);*/
};

const serverError = (error: any) => {
  if (error.code === "EADDRINUSE") {
    logger.debug(`⛔️ Server wasn't able to start properly.`);
    logger.error(`The port ${error.port} is already used by another application.`);
  } else {
    logger.debug(`⛔️ Server wasn't able to start properly.`);
    logger.error(error);
    trace(error);
  }

  serverStop(server);

  return;
};

const serverConnection = (conn: any) => {
  const key = `${conn.remoteAddress}:${conn.remotePort}`;
  currentState.connections[key] = conn;

  conn.on("close", () => {
    delete currentState.connections[key];
  });
};

const sequelizeConn = createSequelizeAdapter();
//const firebirdConn = createFirebirdAdapter();

const server: http.Server = http
  .createServer(app)
  .once("listening", () =>
    process.on("SIGINT", () => {
      //firebirdConn.disconnect();
      serverStop(server);
    })
  )
  .on("close", () =>
    logger.info(`Shut down at: ${DateTime.now().toLocaleString(DateTime.DATETIME_FULL)}`)
  )
  .on("connection", serverConnection)
  .on("error", serverError);

try {
  //firebirdConn.sync().then(() => {
  sequelizeConn.sync({ force: false, alter: true }).then(() => {
    initStructure(sequelizeConn.connection);
    insertUsers();

    // Launch server
    server.listen(currentState.server.port, () => {
      const now = DateTime.now();
      logger.info(`Time: ${now.toLocaleString(DateTime.DATETIME_FULL)} ${now.zoneName}`);
      logger.info(`Launched in: ${now.diff(currentState.launchedAt).toMillis()} ms`);
      logger.info(`Environment: ${currentState.environment}`);
      logger.info(`Process PID: ${process.pid}`);
      logger.info("To shut down your server, press <CTRL> + C at any time");
      logger.info(`⚡️ Server: http://${currentState.server.hostname}:${currentState.server.port}`);
    });
  });
  //});
} catch (error) {
  serverError(error);
}

process.on("uncaughtException", (error: any) => {
  //firebirdConn.disconnect();
  logger.error(`${new Date().toUTCString()} uncaughtException:`, error.message);
  logger.error(error.stack);
  //process.exit(1);
});
