import 'dotenv/config';
import { validateEnv } from './utils/env';
validateEnv();

import Fastify from 'fastify';
import { PrismaClient } from '@prisma/client';
import helmet from '@fastify/helmet';
import rateLimit from '@fastify/rate-limit';
import cors from '@fastify/cors';
import fastifyStatic from '@fastify/static';
import * as path from 'node:path';

import authPlugin from './plugins/auth';
import stripePlugin from './plugins/stripe';
import aiPlugin from './plugins/ai';
import googleAuthPlugin from './plugins/google-auth';

import authRoutes from './routes/auth';
import recipesRoutes from './routes/recipes';
import usersRoutes from './routes/users';

const fastify = Fastify({
  logger: {
    level: process.env.LOG_LEVEL || 'info',
  },
  bodyLimit: 10 * 1024 * 1024, // 10 MB
});

const prisma = new PrismaClient();
fastify.decorate('prisma', prisma);

async function bootstrap(): Promise<void> {
  // --- Sécurité ---
  await fastify.register(helmet, {
    contentSecurityPolicy: false,
    // Autorise le frontend (cross-origin) à charger les images/audio servis
    // depuis /uploads/*. Sans ça, le navigateur bloque avec
    // ERR_BLOCKED_BY_RESPONSE.NotSameOrigin.
    crossOriginResourcePolicy: { policy: 'cross-origin' },
  });

  await fastify.register(rateLimit, {
    max: 100,
    timeWindow: '1 minute',
  });

  const allowedOrigins = (
    process.env.CORS_ORIGINS || 'http://localhost:5173,http://127.0.0.1:5173'
  )
    .split(',')
    .map((s) => s.trim())
    .filter(Boolean);

  await fastify.register(cors, {
    origin: (origin, cb) => {
      if (!origin) return cb(null, true);
      if (allowedOrigins.includes(origin)) return cb(null, true);
      cb(new Error(`Origin ${origin} non autorisée`), false);
    },
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
  });

  // --- Fichiers statiques (fallback local pour images/audio) ---
  await fastify.register(fastifyStatic, {
    root: path.resolve('./uploads'),
    prefix: '/uploads/',
    decorateReply: false,
  });

  // --- Plugins applicatifs ---
  await fastify.register(authPlugin);
  await fastify.register(stripePlugin);
  await fastify.register(aiPlugin);
  await fastify.register(googleAuthPlugin);

  // --- Routes ---
  await fastify.register(authRoutes, { prefix: '/auth' });
  await fastify.register(recipesRoutes, { prefix: '/recipes' });
  await fastify.register(usersRoutes, { prefix: '/users' });

  fastify.get('/health', async () => ({ status: 'ok', uptime: process.uptime() }));

  fastify.addHook('onClose', async () => {
    await prisma.$disconnect();
  });
}

const shutdown = async (signal: string): Promise<void> => {
  fastify.log.info(`${signal} reçu, arrêt en cours...`);
  try {
    await fastify.close();
    process.exit(0);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};
process.on('SIGINT', () => void shutdown('SIGINT'));
process.on('SIGTERM', () => void shutdown('SIGTERM'));

async function start(): Promise<void> {
  try {
    await bootstrap();
    const port = Number(process.env.PORT) || 3000;
    await fastify.listen({ port, host: '0.0.0.0' });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
}

void start();
