// backend/src/routes/codex.js
// All routes require authentication. Never exposed publicly.
// Handles per-client ChatGPT (Codex) connection and image generation.

import { Router }      from 'express';
import rateLimit       from 'express-rate-limit';
import path            from 'path';
import fs              from 'fs/promises';
import { requireAuth, requireActive } from '../middleware/auth.js';
import {
  saveCredentials,
  removeCredentials,
  getConnectionStatus,
  CodexError,
} from '../services/codex-image.js';
import {
  enqueueImageGeneration,
  getJobStatus,
} from '../jobs/codex-image-worker.js';
import { query } from '../utils/db.js';
import { logger } from '../utils/logger.js';

const router = Router();

// Rate limit for image generation: 20/hour per user
const generateLimiter = rateLimit({
  windowMs: 60 * 60 * 1000,
  max: 20,
  keyGenerator: (req) => `codex-gen-${req.user?.id}`,
  message: { error: 'rate_limit', message: 'Image generation limit reached (20/hour). Try again later.' },
  standardHeaders: true,
  legacyHeaders: false,
});

// ─── 1. Connect ChatGPT — upload auth.json ────────────────────────────────────

router.post('/connect', requireAuth, async (req, res) => {
  try {
    const { authJson } = req.body;

    if (!authJson || typeof authJson !== 'string') {
      return res.status(400).json({
        error: 'invalid_input',
        message: 'authJson field is required (contents of your auth.json file)',
      });
    }

    if (authJson.length > 50000) {
      return res.status(400).json({ error: 'invalid_input', message: 'auth.json too large' });
    }

    // Validate it's parseable JSON
    let parsed;
    try { parsed = JSON.parse(authJson); } catch {
      return res.status(400).json({ error: 'invalid_json', message: 'auth.json is not valid JSON' });
    }

    if (typeof parsed !== 'object' || Array.isArray(parsed)) {
      return res.status(400).json({ error: 'invalid_format', message: 'auth.json must be a JSON object' });
    }

    await saveCredentials(req.user.id, authJson);

    logger.info(`User ${req.user.id} connected Codex/ChatGPT`);
    res.json({ success: true, message: 'ChatGPT connected successfully' });
  } catch (err) {
    if (err instanceof CodexError) {
      return res.status(400).json({ error: err.code, message: err.message });
    }
    logger.error('Codex connect error', { userId: req.user.id, error: err.message });
    res.status(500).json({ error: 'connect_failed', message: 'Failed to save credentials' });
  }
});

// ─── 2. Disconnect ChatGPT ────────────────────────────────────────────────────

router.delete('/disconnect', requireAuth, async (req, res) => {
  try {
    await removeCredentials(req.user.id);
    logger.info(`User ${req.user.id} disconnected Codex/ChatGPT`);
    res.json({ success: true });
  } catch (err) {
    logger.error('Codex disconnect error', { userId: req.user.id, error: err.message });
    res.status(500).json({ error: 'disconnect_failed', message: 'Failed to remove credentials' });
  }
});

// ─── 3. Connection status ─────────────────────────────────────────────────────

router.get('/status', requireAuth, async (req, res) => {
  try {
    const status = await getConnectionStatus(req.user.id);
    res.json(status);
  } catch (err) {
    res.status(500).json({ error: 'status_failed', message: err.message });
  }
});

// ─── 4. Generate image ────────────────────────────────────────────────────────

router.post('/generate-image', requireAuth, requireActive, generateLimiter, async (req, res) => {
  try {
    const { prompt, file_name } = req.body;

    if (!prompt || typeof prompt !== 'string' || prompt.trim().length < 3) {
      return res.status(400).json({ error: 'invalid_prompt', message: 'Prompt must be at least 3 characters' });
    }
    if (prompt.length > 2000) {
      return res.status(400).json({ error: 'prompt_too_long', message: 'Prompt must be under 2000 characters' });
    }

    // Verify user has Codex connected
    const connectionStatus = await getConnectionStatus(req.user.id);
    if (!connectionStatus.connected) {
      return res.status(402).json({
        error: 'not_connected',
        message: 'Connect your ChatGPT account in Settings → ChatGPT to generate images',
      });
    }

    const jobId = await enqueueImageGeneration(req.user.id, {
      prompt:  prompt.trim(),
      fileName: file_name,
    });

    res.json({ success: true, jobId, message: 'Image generation queued' });
  } catch (err) {
    logger.error('Codex generate error', { userId: req.user.id, error: err.message });
    res.status(500).json({ error: 'queue_failed', message: 'Failed to queue image generation' });
  }
});

// ─── 5. Job status (polling) ──────────────────────────────────────────────────

router.get('/job/:jobId', requireAuth, async (req, res) => {
  try {
    const status = await getJobStatus(req.params.jobId);
    res.json(status);
  } catch (err) {
    res.status(500).json({ error: 'status_failed', message: err.message });
  }
});

// ─── 6. Serve generated image (authenticated) ─────────────────────────────────

router.get('/image/:contentId', requireAuth, async (req, res) => {
  try {
    const { rows } = await query(
      `SELECT file_path, user_id FROM generated_content
       WHERE id = $1 AND content_type = 'image'`,
      [req.params.contentId]
    );

    if (!rows[0]) {
      return res.status(404).json({ error: 'not_found' });
    }

    // Security: user can only access their own images
    if (rows[0].user_id !== req.user.id && req.user.role !== 'superadmin') {
      return res.status(403).json({ error: 'forbidden' });
    }

    const filePath = rows[0].file_path;
    if (!filePath) {
      return res.status(404).json({ error: 'file_not_found' });
    }

    // Verify file exists
    try {
      await fs.access(filePath);
    } catch {
      return res.status(404).json({ error: 'file_missing', message: 'Image file no longer exists on disk' });
    }

    // Verify extension
    if (!filePath.toLowerCase().endsWith('.png')) {
      return res.status(400).json({ error: 'invalid_type' });
    }

    res.setHeader('Content-Type', 'image/png');
    res.setHeader('Cache-Control', 'private, max-age=3600');
    res.setHeader('X-Content-Type-Options', 'nosniff');

    const fileBuffer = await fs.readFile(filePath);
    res.send(fileBuffer);
  } catch (err) {
    logger.error('Codex serve image error', { error: err.message });
    res.status(500).json({ error: 'serve_failed', message: err.message });
  }
});

export default router;
