import Fastify from 'fastify';
import cors from '@fastify/cors';
import multipart from '@fastify/multipart';
import { env } from './config/env';
import { logger } from './utils/logger';
import { videosRoutes } from './modules/media/routes/videos.routes';
import { videoStreamingRoutes } from './modules/media/routes/video-streaming.routes';
import { reactionsRoutes } from './modules/media/routes/reactions.routes';
import { publicRoutes } from './modules/media/routes/public.routes';
import { chatStreamRoutes } from './modules/media/routes/chat-stream.routes';
import { commentsRoutes } from './modules/media/routes/comments.routes';
import { uploadRoutes } from './modules/media/routes/upload.routes';
import { videoActionsRoutes } from './modules/media/routes/video-actions.routes';
import { videoScheduleRoutes } from './modules/media/routes/video-schedule.routes';
import { videoTrackingRoutes } from './modules/media/routes/video-tracking.routes';
import { commentAdminRoutes } from './modules/media/routes/comment-admin.routes';
import { chatNotificationsRoutes } from './modules/media/routes/chat-notifications.routes';
import { chatThreadsRoutes } from './modules/media/routes/chat-threads.routes';
import { userProfileRoutes } from './modules/media/routes/user-profile.routes';
import { shortsRoutes } from './modules/media/routes/shorts.routes';
import { upvoteRoutes } from './modules/media/routes/upvote.routes';
import { videoScheduleQueueService } from './services/video-schedule-queue.service';
import { videoFetchQueueService } from './services/video-fetch-queue.service';
import { hlsTranscodeQueueService } from './services/hls-transcode-queue.service';
import { fetchRoutes } from './modules/media/routes/fetch.routes';
import { hlsRoutes } from './modules/media/routes/hls.routes';
import { playlistsPublicRoutes } from './modules/media/routes/playlists-public.routes';
import { playlistsUserRoutes } from './modules/media/routes/playlists-user.routes';
import { playlistsAdminRoutes } from './modules/media/routes/playlists-admin.routes';
import { photosRoutes } from './modules/media/routes/photos.routes';
import { photoUploadRoutes } from './modules/media/routes/photo-upload.routes';
import { photoAlbumsRoutes } from './modules/media/routes/photo-albums.routes';
import { photosPublicRoutes } from './modules/media/routes/photos-public.routes';
import { photoEngagementRoutes } from './modules/media/routes/photo-engagement.routes';
import { documentUploadRoutes } from './modules/media/routes/document-upload.routes';
import { documentsRoutes } from './modules/media/routes/documents.routes';
import { mediaErrorHandler } from './modules/media/middleware/error-handler';

// Add BigInt serialization support for Prisma BigInt fields
// This converts BigInt values to strings when JSON.stringify() is called
(BigInt.prototype as any).toJSON = function() {
  return this.toString();
};

const fastify = Fastify({
  logger: {
    level: env.NODE_ENV === 'production' ? 'info' : 'debug',
  },
  maxParamLength: 500,
  trustProxy: true,
});

fastify.setErrorHandler(mediaErrorHandler);

// Graceful shutdown handler
process.on('SIGTERM', async () => {
  logger.info('SIGTERM received, shutting down gracefully...');
  await videoScheduleQueueService.close();
  await videoFetchQueueService.close();
  await hlsTranscodeQueueService.close();
  fastify.close(() => {
    logger.info('Media API server closed');
    process.exit(0);
  });
});

// Global error handlers
process.on('unhandledRejection', (reason, promise) => {
  logger.error('Unhandled Promise Rejection in Media API', { reason: JSON.stringify(reason), promise: JSON.stringify(promise) });
});

process.on('uncaughtException', (error) => {
  logger.error('Uncaught Exception in Media API', { error: error instanceof Error ? error.message : JSON.stringify(error) });
  fastify.close(() => {
    process.exit(1);
  });
});

// Start server
const start = async () => {
  try {
    // CORS configuration — allow admin app + MkDocs docs site
    const allowedOrigins = env.CORS_ORIGINS.split(',').map(o => o.trim());

    // Auto-add MkDocs origins so video cards/players work in docs
    const mkdocsOrigin = `http://localhost:${env.MKDOCS_PORT || 4003}`;
    if (!allowedOrigins.includes(mkdocsOrigin)) {
      allowedOrigins.push(mkdocsOrigin);
    }
    // Also allow the docs subdomain in production (docs.domain.org)
    for (const origin of [...allowedOrigins]) {
      const match = origin.match(/^(https?:\/\/)app\./);
      if (match) {
        const docsOrigin = origin.replace(/^(https?:\/\/)app\./, '$1docs.');
        if (!allowedOrigins.includes(docsOrigin)) {
          allowedOrigins.push(docsOrigin);
        }
      }
    }

    await fastify.register(cors, {
      origin: (origin, cb) => {
        // Allow requests with no origin (mobile apps, curl, etc.)
        if (!origin) {
          cb(null, true);
          return;
        }

        // Check if origin is in allowed list
        if (allowedOrigins.includes(origin)) {
          cb(null, true);
        } else {
          cb(new Error('CORS not allowed'), false);
        }
      },
      credentials: true,
    });

    // Multipart support for file uploads (10GB limit)
    await fastify.register(multipart, {
      limits: {
        fileSize: env.MAX_UPLOAD_SIZE_GB * 1024 * 1024 * 1024,
      },
    });

    // Health check
    fastify.get('/health', async () => {
      return {
        status: 'ok',
        timestamp: new Date().toISOString(),
        service: 'media-api'
      };
    });

    // Register routes
    await fastify.register(videosRoutes, { prefix: '/api/videos' });
    await fastify.register(videoStreamingRoutes, { prefix: '/api/videos' });
    await fastify.register(uploadRoutes, { prefix: '/api/videos' });
    await fastify.register(videoActionsRoutes, { prefix: '/api/videos' });
    await fastify.register(videoScheduleRoutes, { prefix: '/api/videos' });
    await fastify.register(hlsRoutes, { prefix: '/api' });
    await fastify.register(videoTrackingRoutes, { prefix: '/api/track' });
    await fastify.register(reactionsRoutes, { prefix: '/api/reactions' });
    await fastify.register(publicRoutes, { prefix: '/api' });
    await fastify.register(commentsRoutes, { prefix: '/api' });
    await fastify.register(chatStreamRoutes, { prefix: '/api' });
    await fastify.register(commentAdminRoutes, { prefix: '/api/media' });
    await fastify.register(chatNotificationsRoutes, { prefix: '/api/media' });
    // Signed URL generation (replaces ?token=JWT pattern, 2026-04-12).
    const { signRoutes } = await import('./modules/media/routes/sign.routes');
    await fastify.register(signRoutes, { prefix: '/api/media' });
    await fastify.register(chatThreadsRoutes, { prefix: '/api/media' });
    await fastify.register(userProfileRoutes, { prefix: '/api/media' });
    await fastify.register(fetchRoutes, { prefix: '/api/videos' });
    await fastify.register(shortsRoutes, { prefix: '/api' });
    await fastify.register(upvoteRoutes, { prefix: '/api' });
    await fastify.register(playlistsPublicRoutes, { prefix: '/api/playlists' });
    await fastify.register(playlistsUserRoutes, { prefix: '/api/playlists' });
    await fastify.register(playlistsAdminRoutes, { prefix: '/api/media' });

    // Photo gallery routes
    await fastify.register(photosRoutes, { prefix: '/api/photos' });
    await fastify.register(photoUploadRoutes, { prefix: '/api/photos' });
    await fastify.register(photoAlbumsRoutes, { prefix: '/api/albums' });
    await fastify.register(photosPublicRoutes, { prefix: '/api' });
    await fastify.register(photoEngagementRoutes, { prefix: '/api' });

    // Document routes (PDFs, docx, etc. for volunteer resources)
    await fastify.register(documentUploadRoutes, { prefix: '/api/documents' });
    await fastify.register(documentsRoutes, { prefix: '/api/documents' });

    // 404 handler for unmatched routes
    fastify.setNotFoundHandler((_request, reply) => {
      reply.status(404).send({ error: { message: 'Route not found', code: 'NOT_FOUND' } });
    });

    const port = env.MEDIA_API_PORT;
    const host = '0.0.0.0';

    await fastify.listen({ port, host });
    logger.info(`Media API listening on http://${host}:${port}`);

    // Start video schedule queue worker
    videoScheduleQueueService.startWorker();
    logger.info('Video schedule queue worker initialized');

    // Start video fetch queue worker
    videoFetchQueueService.startWorker();
    logger.info('Video fetch queue worker initialized');

    // Start HLS transcode worker (always on; the ENABLE_HLS_TRANSCODE flag
    // gates enqueue, not worker registration, so existing PENDING jobs from
    // a prior run still process if the flag was flipped back on).
    hlsTranscodeQueueService.startWorker();
    logger.info('HLS transcode queue worker initialized');

    if (env.ENABLE_MEDIA_FEATURES !== 'true') {
      logger.warn('Media features are disabled (ENABLE_MEDIA_FEATURES=false)');
    }
  } catch (err) {
    logger.error('Media API startup error', { error: err instanceof Error ? err.message : JSON.stringify(err) });
    process.exit(1);
  }
};

start();
