// ABOUTME: Workers entry point and public exports
// ABOUTME: Exports queue definitions, worker factories, and a bootstrap function for the worker process

import { PrismaClient } from '@prisma/client';
import { Worker } from 'bullmq';
import { TabApiClient } from '../api/tab';
import config from '../config';
import logger from '../utils/logger';
import { closeQueues } from './queue';
import { createMorningScrapeWorker } from './morning-scrape.worker';
import { createPreRaceWorker } from './pre-race.worker';
import { createPostRaceWorker } from './post-race.worker';
import { createCleanupWorker } from './cleanup.worker';
import { createDeadLetterWorker } from './dead-letter.worker';

// ============================================================================
// Re-exports
// ============================================================================

export * from './queue';
export * from './morning-scrape.worker';
export * from './pre-race.worker';
export * from './post-race.worker';
export * from './cleanup.worker';
export * from './dead-letter.worker';

// ============================================================================
// Worker Manager
// ============================================================================

interface WorkerManager {
  workers: Worker[];
  prisma: PrismaClient;
  apiClient: TabApiClient;
}

/**
 * Initialize all workers and their shared dependencies
 */
export function initializeWorkers(): WorkerManager {
  logger.info('Initializing workers...');

  // Shared dependencies
  const prisma = new PrismaClient({
    log: config.env === 'development' ? ['error', 'warn'] : ['error'],
  });

  const apiClient = new TabApiClient({
    baseUrl: config.tabApi.baseUrl,
    rateLimitPerMinute: config.rateLimiting.perMinute,
    maxRetries: config.rateLimiting.retryAttempts,
    retryDelay: config.rateLimiting.retryDelayMs,
    timeout: 10000,
  });

  // Create all workers
  const workers: Worker[] = [
    createMorningScrapeWorker(apiClient, prisma),
    createPreRaceWorker(apiClient, prisma),
    createPostRaceWorker(apiClient, prisma),
    createCleanupWorker(prisma),
    createDeadLetterWorker(),
  ];

  logger.info({ workerCount: workers.length }, 'All workers initialized');

  return { workers, prisma, apiClient };
}

/**
 * Start all workers (they begin processing immediately upon creation,
 * but this ensures the process stays alive)
 */
export async function startWorkers(): Promise<void> {
  const manager = initializeWorkers();

  logger.info('Workers started and waiting for jobs');

  // Graceful shutdown handler
  const shutdown = async (signal: string) => {
    logger.info({ signal }, 'Shutdown signal received, closing workers...');

    // Stop all workers
    await Promise.allSettled(
      manager.workers.map((w) => w.close())
    );

    // Close queues and Redis
    await closeQueues();

    // Disconnect Prisma
    await manager.prisma.$disconnect();

    logger.info('All workers shut down gracefully');
    process.exit(0);
  };

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

  // Keep process alive
  await new Promise(() => {
    // This promise never resolves - the process runs until signaled
  });
}

// ============================================================================
// Entry point when this file is run directly
// ============================================================================

if (require.main === module) {
  startWorkers().catch((error) => {
    logger.error(
      { error: error instanceof Error ? error.message : 'Unknown error' },
      'Failed to start workers'
    );
    process.exit(1);
  });
}
