import { Response, NextFunction } from 'express';

// Validation rules
const VALIDATION_RULES = {
  prompt: {
    minLength: 3,
    maxLength: 2000,
    required: true,
  },
  filename: {
    minLength: 1,
    maxLength: 100,
    required: true,
    pattern: /^[a-zA-Z0-9_-]+$/, // Only alphanumeric, underscore, hyphen
  },
};

/**
 * Sanitize filename to prevent directory traversal and invalid characters
 */
export const sanitizeFilename = (filename: string): string => {
  return filename
    .replace(/[^a-zA-Z0-9_-]/g, '_') // Replace invalid chars with underscore
    .replace(/_{2,}/g, '_') // Replace multiple underscores with single
    .replace(/^_+|_+$/g, '') // Remove leading/trailing underscores
    .substring(0, 100); // Limit length
};

/**
 * Validate the generate image request
 */
export const validateGenerateRequest = (
  req: any,
  res: Response,
  next: NextFunction,
): void | Response => {
  const timestamp = new Date().toISOString();
  let { prompt, filename, autoEnhance, enhancementOptions } = req.body;
  const errors: string[] = [];

  // Convert string values from multipart form data
  if (typeof autoEnhance === 'string') {
    autoEnhance = autoEnhance.toLowerCase() === 'true';
    req.body.autoEnhance = autoEnhance;
  }

  if (typeof enhancementOptions === 'string') {
    try {
      enhancementOptions = JSON.parse(enhancementOptions);
      req.body.enhancementOptions = enhancementOptions;
    } catch {
      errors.push('enhancementOptions must be valid JSON');
    }
  }

  console.log(`[${timestamp}] [${req.requestId}] Validating generate request`);

  // Validate prompt
  if (!prompt) {
    errors.push('Prompt is required');
  } else if (typeof prompt !== 'string') {
    errors.push('Prompt must be a string');
  } else if (prompt.trim().length < VALIDATION_RULES.prompt.minLength) {
    errors.push(`Prompt must be at least ${VALIDATION_RULES.prompt.minLength} characters`);
  } else if (prompt.length > VALIDATION_RULES.prompt.maxLength) {
    errors.push(`Prompt must be less than ${VALIDATION_RULES.prompt.maxLength} characters`);
  }

  // Validate filename
  if (!filename) {
    errors.push('Filename is required');
  } else if (typeof filename !== 'string') {
    errors.push('Filename must be a string');
  } else if (filename.trim().length < VALIDATION_RULES.filename.minLength) {
    errors.push('Filename cannot be empty');
  } else if (filename.length > VALIDATION_RULES.filename.maxLength) {
    errors.push(`Filename must be less than ${VALIDATION_RULES.filename.maxLength} characters`);
  } else if (!VALIDATION_RULES.filename.pattern.test(filename)) {
    errors.push('Filename can only contain letters, numbers, underscores, and hyphens');
  }

  // Validate autoEnhance (optional boolean)
  if (autoEnhance !== undefined && typeof autoEnhance !== 'boolean') {
    errors.push('autoEnhance must be a boolean');
  }

  // Validate enhancementOptions (optional object)
  if (enhancementOptions !== undefined) {
    if (typeof enhancementOptions !== 'object' || Array.isArray(enhancementOptions)) {
      errors.push('enhancementOptions must be an object');
    } else {
      const { imageStyle, aspectRatio, mood, lighting, cameraAngle, negativePrompts } =
        enhancementOptions;

      if (
        imageStyle !== undefined &&
        !['photorealistic', 'illustration', 'minimalist', 'sticker', 'product', 'comic'].includes(
          imageStyle,
        )
      ) {
        errors.push('Invalid imageStyle in enhancementOptions');
      }

      if (
        aspectRatio !== undefined &&
        !['square', 'portrait', 'landscape', 'wide', 'ultrawide'].includes(aspectRatio)
      ) {
        errors.push('Invalid aspectRatio in enhancementOptions');
      }

      if (mood !== undefined && (typeof mood !== 'string' || mood.length > 100)) {
        errors.push('mood must be a string with max 100 characters');
      }

      if (lighting !== undefined && (typeof lighting !== 'string' || lighting.length > 100)) {
        errors.push('lighting must be a string with max 100 characters');
      }

      if (
        cameraAngle !== undefined &&
        (typeof cameraAngle !== 'string' || cameraAngle.length > 100)
      ) {
        errors.push('cameraAngle must be a string with max 100 characters');
      }

      if (negativePrompts !== undefined) {
        if (!Array.isArray(negativePrompts) || negativePrompts.length > 10) {
          errors.push('negativePrompts must be an array with max 10 items');
        } else {
          for (const item of negativePrompts) {
            if (typeof item !== 'string' || item.length > 100) {
              errors.push('Each negative prompt must be a string with max 100 characters');
              break;
            }
          }
        }
      }
    }
  }

  // Check for XSS attempts in prompt
  const xssPatterns = [/<script/i, /javascript:/i, /on\w+\s*=/i, /<iframe/i, /<object/i, /<embed/i];

  if (prompt && xssPatterns.some((pattern) => pattern.test(prompt))) {
    errors.push('Invalid characters detected in prompt');
  }

  // Log validation results
  if (errors.length > 0) {
    console.log(`[${timestamp}] [${req.requestId}] Validation failed: ${errors.join(', ')}`);
    return res.status(400).json({
      success: false,
      error: 'Validation failed',
      message: errors.join(', '),
    });
  }

  // Sanitize filename
  if (filename) {
    req.body.filename = sanitizeFilename(filename.trim());
    if (req.body.filename !== filename.trim()) {
      console.log(
        `[${timestamp}] [${req.requestId}] Filename sanitized: "${filename}" -> "${req.body.filename}"`,
      );
    }
  }

  // Trim and clean prompt
  if (prompt) {
    req.body.prompt = prompt.trim();
  }

  console.log(`[${timestamp}] [${req.requestId}] Validation passed`);
  next();
};

/**
 * Log request details for debugging
 */
export const logRequestDetails = (req: any, _res: Response, next: NextFunction): void => {
  const timestamp = new Date().toISOString();
  const { prompt, filename, autoEnhance, enhancementOptions } = req.body;
  const files = (req.files as Express.Multer.File[]) || [];

  console.log(`[${timestamp}] [${req.requestId}] === REQUEST DETAILS ===`);
  console.log(`[${timestamp}] [${req.requestId}] Method: ${req.method}`);
  console.log(`[${timestamp}] [${req.requestId}] Path: ${req.path}`);
  console.log(
    `[${timestamp}] [${req.requestId}] Prompt: "${prompt?.substring(0, 100)}${prompt?.length > 100 ? '...' : ''}"`,
  );
  console.log(`[${timestamp}] [${req.requestId}] Filename: "${filename}"`);
  console.log(`[${timestamp}] [${req.requestId}] Auto-enhance: ${autoEnhance || false}`);
  if (enhancementOptions) {
    console.log(`[${timestamp}] [${req.requestId}] Enhancement options:`, enhancementOptions);
  }
  console.log(`[${timestamp}] [${req.requestId}] Reference files: ${files.length}`);

  if (files.length > 0) {
    files.forEach((file, index) => {
      console.log(
        `[${timestamp}] [${req.requestId}] File ${index + 1}: ${file.originalname} (${file.mimetype}, ${Math.round(file.size / 1024)}KB)`,
      );
    });
  }

  console.log(`[${timestamp}] [${req.requestId}] ===========================`);
  next();
};
