// backend/src/index.js
import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
import path from 'path';
import { fileURLToPath } from 'url';

import { logger } from './utils/logger.js';
import authRoutes from './routes/auth.js';
import stripeRoutes from './routes/stripe.js';
import profileRoutes from './routes/profile.js';
import pipelineRoutes from './routes/pipeline.js';
import contentRoutes from './routes/content.js';
import adminRoutes from './routes/admin.js';
import nicheRoutes from './routes/niche.js';
import demoRoutes from './routes/demo.js';
import codexRoutes from './routes/codex.js';
import { startPipelineWorker } from './jobs/pipeline-worker.js';
import { startScheduler } from './jobs/scheduler.js';
import { startCodexImageWorker } from './jobs/codex-image-worker.js';

const app = express();

// ─── Stripe webhook needs raw body ────────────────────────────────
app.use('/api/stripe/webhook', express.raw({ type: 'application/json' }), (req, res, next) => {
  req.rawBody = req.body;
  next();
});

// ─── Middleware ────────────────────────────────────────────────────
app.use(helmet({
  contentSecurityPolicy: false, // SPA assets; relax CSP
  crossOriginEmbedderPolicy: false,
}));
app.use(cors({
  origin: process.env.APP_URL || true, // same-origin when serving SPA
  credentials: true,
}));
app.use(express.json({ limit: '2mb' }));

// Rate limiting
app.use('/api/auth', rateLimit({ windowMs: 15 * 60 * 1000, max: 20, message: { error: 'Too many requests' } }));
app.use('/api/pipeline/run', rateLimit({ windowMs: 60 * 60 * 1000, max: 5, message: { error: 'Pipeline rate limit reached' } }));
app.use('/api', rateLimit({ windowMs: 60 * 1000, max: 200 }));

// ─── Routes ───────────────────────────────────────────────────────
app.use('/api/auth', authRoutes);
app.use('/api/stripe', stripeRoutes);
app.use('/api/profile', profileRoutes);
app.use('/api/pipeline', pipelineRoutes);
app.use('/api/content', contentRoutes);
app.use('/api/admin', adminRoutes);
app.use('/api/niche', nicheRoutes);
app.use('/api/demo', demoRoutes);
app.use('/api/codex', codexRoutes);

// ─── Health check ─────────────────────────────────────────────────
app.get('/health', (req, res) => res.json({ status: 'ok', env: process.env.NODE_ENV }));

// ─── Serve frontend (SPA) ─────────────────────────────────────────
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const frontendDist = path.resolve(__dirname, '../../frontend/dist');
app.use(express.static(frontendDist));

// SPA fallback: any non-API route serves index.html (React Router handles it)
app.get(/^(?!\/api).*/, (req, res, next) => {
  res.sendFile(path.join(frontendDist, 'index.html'), (err) => {
    if (err) next();
  });
});

// ─── Error handler ────────────────────────────────────────────────
app.use((err, req, res, next) => {
  logger.error('Unhandled error', err);
  res.status(500).json({ error: 'Internal server error' });
});

// ─── Start ────────────────────────────────────────────────────────
const PORT = process.env.PORT || 4000;

// In PM2 cluster mode, only instance 0 runs workers + scheduler.
// Prevents duplicate job processing and double-fired daily pipelines.
const isWorkerInstance =
  process.env.NODE_APP_INSTANCE === undefined ||
  process.env.NODE_APP_INSTANCE === '0';

app.listen(PORT, () => {
  logger.info(`Server running on port ${PORT} (instance ${process.env.NODE_APP_INSTANCE ?? 'single'})`);

  if (isWorkerInstance) {
    startPipelineWorker();
    startScheduler();
    if (process.env.CODEX_ENABLED !== 'false') {
      startCodexImageWorker();
      logger.info('Codex image worker started');
    }
    logger.info('Workers + scheduler started on this instance');
  } else {
    logger.info('Web-only instance (workers run on instance 0)');
  }
});
