/**
 * Graceful shutdown utilities
 * Handles signal processing, connection draining, and in-flight request completion
 */

import { createLogger } from './logger';

const logger = createLogger('graceful-shutdown');

export interface GracefulShutdownOptions {
  timeout?: number; // Maximum time to wait for shutdown (default: 30s)
  onShutdown?: () => Promise<void>; // Custom shutdown hook
}

/**
 * Setup graceful shutdown for a Fastify server
 */
export function setupGracefulShutdown(
  server: { close: () => Promise<void> },
  options: GracefulShutdownOptions = {}
): void {
  const { timeout = 30000, onShutdown } = options;

  const shutdown = async (signal: string): Promise<void> => {
    logger.info({ signal }, 'Received shutdown signal, starting graceful shutdown...');

    // Stop accepting new connections
    server.close = (() => {
      const originalClose = server.close.bind(server);
      return async () => {
        logger.info('Server closed, no longer accepting new connections');
        return originalClose();
      };
    })();

    try {
      // Wait for in-flight requests with timeout
      const shutdownPromise = Promise.all([
        // Wait for server to close
        server.close().catch((err) => {
          logger.warn({ err }, 'Error closing server');
        }),
        // Run custom shutdown hook if provided
        onShutdown?.().catch((err) => {
          logger.warn({ err }, 'Error in shutdown hook');
        }),
      ]);

      // Apply timeout
      await Promise.race([
        shutdownPromise,
        new Promise<void>((resolve) => {
          setTimeout(() => {
            logger.warn('Shutdown timeout reached, forcing exit');
            resolve();
          }, timeout);
        }),
      ]);

      logger.info('Graceful shutdown complete');
      process.exit(0);
    } catch (err) {
      logger.error({ err }, 'Error during graceful shutdown');
      process.exit(1);
    }
  };

  // Handle termination signals
  process.on('SIGTERM', () => shutdown('SIGTERM'));
  process.on('SIGINT', () => shutdown('SIGINT'));

  // Handle uncaught exceptions
  process.on('uncaughtException', (err) => {
    logger.error({ err }, 'Uncaught exception, shutting down');
    shutdown('uncaughtException').catch(() => {
      process.exit(1);
    });
  });

  // Handle unhandled promise rejections
  process.on('unhandledRejection', (reason) => {
    logger.error({ reason }, 'Unhandled rejection, shutting down');
    shutdown('unhandledRejection').catch(() => {
      process.exit(1);
    });
  });
}

/**
 * Create a connection drainer for database connections
 */
export function createConnectionDrainer(
  pool: { end: () => Promise<void> }
): () => Promise<void> {
  return async () => {
    logger.info('Draining database connections...');
    try {
      await pool.end();
      logger.info('Database connections drained');
    } catch (err) {
      logger.warn({ err }, 'Error draining database connections');
    }
  };
}

