import {
  Injectable,
  Logger,
  OnApplicationShutdown,
  BeforeApplicationShutdown,
} from '@nestjs/common';
import { HealthController } from './health.controller';

/**
 * Graceful Shutdown Service - ensures zero-downtime rolling upgrades.
 *
 * Shutdown sequence:
 * 1. Receive SIGTERM (from K8s, docker stop, etc.)
 * 2. Mark service as NOT ready (health/ready returns 503)
 * 3. Wait for drain period (allow in-flight requests to complete)
 * 4. Close connections (DB, Redis, Kafka)
 * 5. Exit process
 *
 * K8s preStop hook should wait ~5s before sending SIGTERM,
 * giving the load balancer time to remove this pod from rotation.
 */
@Injectable()
export class GracefulShutdownService
  implements BeforeApplicationShutdown, OnApplicationShutdown
{
  private readonly logger = new Logger('GracefulShutdown');
  private readonly drainTimeoutMs: number;

  constructor(private readonly healthController: HealthController) {
    this.drainTimeoutMs = parseInt(
      process.env.GRACEFUL_SHUTDOWN_DRAIN_MS || '10000',
      10,
    );
  }

  /**
   * Called before application shutdown begins.
   * Mark as not ready and wait for drain period.
   */
  async beforeApplicationShutdown(signal?: string) {
    this.logger.warn(
      `Shutdown signal received: ${signal || 'unknown'}. Starting graceful shutdown...`,
    );

    // Step 1: Mark as not ready (stop accepting new requests)
    this.healthController.setReady(false);
    this.logger.log('Marked service as NOT ready');

    // Step 2: Wait for drain period (in-flight requests to complete)
    this.logger.log(
      `Waiting ${this.drainTimeoutMs}ms for in-flight requests to drain...`,
    );
    await new Promise((resolve) =>
      setTimeout(resolve, this.drainTimeoutMs),
    );
    this.logger.log('Drain period complete');
  }

  /**
   * Called after application shutdown. Final cleanup logging.
   */
  async onApplicationShutdown(signal?: string) {
    this.logger.log(`Application shutdown complete (signal: ${signal || 'none'})`);
  }
}
