/**
 * Custom server entry point.
 *
 * Boots Next.js, attaches Socket.io to the same HTTP server, and in
 * development mode also registers BullMQ recurring jobs and starts the
 * workers inline (so you don't need the separate crm-worker container).
 *
 * In production the workers run in the crm-worker container (Dockerfile.worker
 * → dist/worker.js) and this file only handles Next.js + Socket.io.
 */

import { createServer } from 'node:http';

import next from 'next';

import { initSocketServer } from '@/lib/socket/server';
import { logger } from '@/lib/logger';

const dev = process.env.NODE_ENV !== 'production';
const port = parseInt(process.env.PORT ?? '3000', 10);

async function main(): Promise<void> {
  const app = next({ dev, port });
  const handle = app.getRequestHandler();

  await app.prepare();

  const httpServer = createServer((req, res) => {
    handle(req, res);
  });

  // Attach Socket.io to the HTTP server (uses Redis adapter for pub/sub)
  initSocketServer(httpServer);
  logger.info('Socket.io initialized');

  // In development, run BullMQ workers inline so a single `pnpm dev` is enough
  if (dev) {
    const { registerRecurringJobs } = await import('@/lib/queue/scheduler');
    const { emailWorker } = await import('@/lib/queue/workers/email');
    const { documentsWorker } = await import('@/lib/queue/workers/documents');
    const { notificationsWorker } = await import('@/lib/queue/workers/notifications');
    const { importWorker } = await import('@/lib/queue/workers/import');
    const { exportWorker } = await import('@/lib/queue/workers/export');

    await registerRecurringJobs();
    logger.info('BullMQ recurring jobs registered (dev mode)');

    // Keep a reference so workers aren't GC'd
    void [emailWorker, documentsWorker, notificationsWorker, importWorker, exportWorker];
  }

  httpServer.listen(port, () => {
    logger.info({ port, env: process.env.NODE_ENV }, 'Port Nimara CRM server listening');
  });
}

main().catch((err) => {
  logger.error(err, 'Failed to start server');
  process.exit(1);
});
