/**
 * Process entry. `./env` is imported first so a bad .env fails the boot before
 * anything binds a port (PLANNING.md §3a). In production this file is reached via
 * the root app.js Passenger shim -> dist/server.js.
 */
import './env';
import { app } from './app';
import { env } from './env';
import { logger } from './lib/logger';
import { destroyDb } from './lib/db';

const server = app.listen(env.PORT, () => {
  logger.info({ port: env.PORT, env: env.NODE_ENV }, 'server listening');
});

let shuttingDown = false;
async function shutdown(signal: string): Promise<void> {
  if (shuttingDown) return;
  shuttingDown = true;
  logger.info({ signal }, 'shutting down');

  server.close((err) => {
    if (err) logger.error({ err }, 'error closing http server');
  });

  try {
    await destroyDb();
  } catch (err) {
    logger.error({ err }, 'error closing db pool');
  }

  // Give in-flight requests a moment, then exit regardless.
  setTimeout(() => process.exit(0), 3000).unref();
}

process.on('SIGTERM', () => void shutdown('SIGTERM'));
process.on('SIGINT', () => void shutdown('SIGINT'));

process.on('unhandledRejection', (reason) => {
  logger.fatal({ reason }, 'unhandledRejection');
  process.exit(1);
});
process.on('uncaughtException', (err) => {
  logger.fatal({ err }, 'uncaughtException');
  process.exit(1);
});
