import { NestFactory } from '@nestjs/core';
import { WorkerModule } from './worker.module';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from './infrastructure/database/prisma.service';
import { RedisService } from './infrastructure/redis/redis.service';
import { Logger } from '@nestjs/common';
import * as os from 'os';

function generateInstanceId(): string {
  const hostname = os.hostname();
  const pid = process.pid;
  const timestamp = Date.now();
  return `worker-${hostname}-${pid}-${timestamp}`;
}

async function validatePrerequisites(
  prisma: PrismaService,
  redis: RedisService,
  config: ConfigService,
  logger: Logger,
): Promise<void> {
  // Validate MySQL
  try {
    await prisma.$queryRaw`SELECT 1`;
    logger.log('MySQL connection verified');
  } catch (err: any) {
    logger.error(`MySQL connection failed: ${err.message}`);
    process.exit(1);
  }

  // Validate Redis
  try {
    await redis.get('__worker_health_check__');
    logger.log('Redis connection verified');
  } catch (err: any) {
    logger.error(`Redis connection failed: ${err.message}`);
    process.exit(1);
  }

  // Validate required config keys
  const requiredKeys = ['database.url', 'redis.host', 'jwt.secret'];
  const missing = requiredKeys.filter(k => {
    const val = config.get(k);
    if (val === undefined || val === null || val === '') return true;
    if (typeof val === 'string' && val.startsWith('change_me')) return true;
    return false;
  });

  if (missing.length > 0) {
    logger.error(`Missing required config keys: ${missing.join(', ')}`);
    process.exit(1);
  }
  logger.log('Required configuration verified');
}

async function bootstrap() {
  const logger = new Logger('WorkerBootstrap');

  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const pkg = (() => { try { return require('../../package.json'); } catch { return { version: '0.0.0' }; } })();
  const instanceId = generateInstanceId();
  process.env.WORKER_INSTANCE_ID = instanceId;
  logger.log(`Worker version ${pkg.version} — instance ${instanceId}`);

  const app = await NestFactory.createApplicationContext(WorkerModule);

  const config = app.get(ConfigService);
  const prisma = app.get(PrismaService);
  const redis = app.get(RedisService);

  await validatePrerequisites(prisma, redis, config, logger);

  // Log queue configuration
  try {
    const { QUEUE_DEFINITIONS } = require('./infrastructure/queue/queue-definitions');
    logger.log('Queue configuration:');
    for (const [name, def] of Object.entries(QUEUE_DEFINITIONS) as [string, any][]) {
      logger.log(
        `  ${name}: concurrency=${def.workerOptions.concurrency} attempts=${def.defaultJobOptions.attempts} backoff=exponential:${def.defaultJobOptions.backoff.delay}ms`,
      );
    }
  } catch {
    logger.warn('Could not load queue definitions for startup log');
  }

  app.enableShutdownHooks();

  logger.log(`Worker ${instanceId} started — waiting for jobs`);

  // Graceful shutdown with forced timeout
  const SHUTDOWN_TIMEOUT_MS = 30_000;
  let shuttingDown = false;

  const shutdown = (signal: string) => {
    if (shuttingDown) return;
    shuttingDown = true;

    logger.log(`Received ${signal} — stopping job acquisition, waiting for active jobs (timeout ${SHUTDOWN_TIMEOUT_MS / 1000}s)...`);

    const forceExit = setTimeout(() => {
      logger.error(`Shutdown timed out after ${SHUTDOWN_TIMEOUT_MS / 1000}s — forcing exit`);
      process.exit(1);
    }, SHUTDOWN_TIMEOUT_MS);

    app.close().then(() => {
      clearTimeout(forceExit);
      logger.log('Worker shut down gracefully');
      process.exit(0);
    }).catch((err: any) => {
      clearTimeout(forceExit);
      logger.error(`Worker shutdown error: ${err.message}`);
      process.exit(1);
    });
  };

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

bootstrap();
