const { ValidationError } = require('./errorHandler');

// Input sanitization utilities
class Sanitizer {
  // Remove HTML tags and dangerous characters
  static sanitizeText(text) {
    if (typeof text !== 'string') return '';
    
    return text
      .replace(/<script[^>]*>.*?<\/script>/gi, '') // Remove script tags
      .replace(/<[^>]*>/g, '') // Remove HTML tags
      .replace(/javascript:/gi, '') // Remove javascript: protocol
      .replace(/on\w+\s*=/gi, '') // Remove event handlers
      .trim();
  }

  // Sanitize filename for uploads
  static sanitizeFilename(filename) {
    if (typeof filename !== 'string') return '';
    
    return filename
      .replace(/[^a-zA-Z0-9._-]/g, '_') // Replace special chars with underscore
      .replace(/_{2,}/g, '_') // Replace multiple underscores with single
      .substring(0, 255); // Limit length
  }

  // Sanitize user input for database
  static sanitizeUserInput(input) {
    if (typeof input === 'string') {
      return this.sanitizeText(input);
    }
    if (typeof input === 'object' && input !== null) {
      const sanitized = {};
      for (const [key, value] of Object.entries(input)) {
        sanitized[key] = this.sanitizeUserInput(value);
      }
      return sanitized;
    }
    return input;
  }
}

// Validation utilities
class Validator {
  // Validate message content
  static validateMessage(content) {
    if (!content || typeof content !== 'string') {
      throw new ValidationError('Message content is required', 'content');
    }
    
    const sanitized = Sanitizer.sanitizeText(content);
    
    if (sanitized.length === 0) {
      throw new ValidationError('Message content cannot be empty', 'content');
    }
    
    if (sanitized.length > 5000) {
      throw new ValidationError('Message content is too long (max 5000 characters)', 'content');
    }
    
    return sanitized;
  }

  // Validate user ID
  static validateUserId(userId) {
    if (!userId) {
      throw new ValidationError('User ID is required', 'userId');
    }
    
    const id = parseInt(userId);
    if (isNaN(id) || id <= 0) {
      throw new ValidationError('Invalid user ID', 'userId');
    }
    
    return id;
  }

  // Validate private chat ID
  static validatePrivateChatId(chatId) {
    if (!chatId) {
      throw new ValidationError('Private chat ID is required', 'privateChatId');
    }
    
    const id = parseInt(chatId);
    if (isNaN(id) || id <= 0) {
      throw new ValidationError('Invalid private chat ID', 'privateChatId');
    }
    
    return id;
  }

  // Validate file upload
  static validateFileUpload(file) {
    if (!file) {
      throw new ValidationError('File is required', 'file');
    }

    // Check file size (10MB limit)
    const maxSize = 10 * 1024 * 1024;
    if (file.size > maxSize) {
      throw new ValidationError('File size exceeds 10MB limit', 'file');
    }

    // Check file type
    const allowedTypes = [
      'image/jpeg', 'image/png', 'image/gif', 'image/webp',
      'application/pdf', 'text/plain', 'application/msword',
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    ];
    
    if (!allowedTypes.includes(file.mimetype)) {
      throw new ValidationError('File type not allowed', 'file');
    }

    // Sanitize filename
    const sanitizedName = Sanitizer.sanitizeFilename(file.originalname);
    if (!sanitizedName) {
      throw new ValidationError('Invalid filename', 'file');
    }

    return {
      ...file,
      originalname: sanitizedName
    };
  }

  // Validate email
  static validateEmail(email) {
    if (!email || typeof email !== 'string') {
      throw new ValidationError('Email is required', 'email');
    }
    
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      throw new ValidationError('Invalid email format', 'email');
    }
    
    return email.toLowerCase().trim();
  }

  // Validate name
  static validateName(name) {
    if (!name || typeof name !== 'string') {
      throw new ValidationError('Name is required', 'name');
    }
    
    const sanitized = Sanitizer.sanitizeText(name);
    
    if (sanitized.length < 2) {
      throw new ValidationError('Name must be at least 2 characters', 'name');
    }
    
    if (sanitized.length > 100) {
      throw new ValidationError('Name is too long (max 100 characters)', 'name');
    }
    
    return sanitized;
  }
}

// Rate limiting store (in-memory, use Redis in production)
const rateLimitStore = new Map();

// Rate limiting middleware
const createRateLimit = (windowMs = 60000, maxRequests = 60) => {
  return (req, res, next) => {
    const key = req.ip || req.connection.remoteAddress;
    const now = Date.now();
    
    if (!rateLimitStore.has(key)) {
      rateLimitStore.set(key, { count: 1, resetTime: now + windowMs });
      return next();
    }
    
    const limit = rateLimitStore.get(key);
    
    if (now > limit.resetTime) {
      // Reset the limit
      rateLimitStore.set(key, { count: 1, resetTime: now + windowMs });
      return next();
    }
    
    if (limit.count >= maxRequests) {
      return res.status(429).json({
        success: false,
        message: 'Too many requests, please try again later'
      });
    }
    
    limit.count++;
    next();
  };
};

// Socket rate limiting
const socketRateLimit = new Map();

const checkSocketRateLimit = (socketId, action, maxRequests = 30, windowMs = 60000) => {
  const key = `${socketId}:${action}`;
  const now = Date.now();
  
  if (!socketRateLimit.has(key)) {
    socketRateLimit.set(key, { count: 1, resetTime: now + windowMs });
    return true;
  }
  
  const limit = socketRateLimit.get(key);
  
  if (now > limit.resetTime) {
    socketRateLimit.set(key, { count: 1, resetTime: now + windowMs });
    return true;
  }
  
  if (limit.count >= maxRequests) {
    return false;
  }
  
  limit.count++;
  return true;
};

module.exports = {
  Sanitizer,
  Validator,
  createRateLimit,
  checkSocketRateLimit
};