// src/middleware/validation.js
// === SECURITY HARDENING: INPUT VALIDATION ===
// Request validation middleware using simple validation

/**
 * Validation middleware for request bodies
 * Uses simple validation without external dependencies
 */

/**
 * Validate phone number format
 */
function validatePhone(phone) {
  if (!phone || typeof phone !== 'string') {
    return { valid: false, error: 'phone_number must be a string' };
  }
  const trimmed = phone.trim();
  if (trimmed.length < 10 || trimmed.length > 20) {
    return { valid: false, error: 'phone_number must be 10-20 characters' };
  }
  return { valid: true };
}

/**
 * Validate OTP code format
 */
function validateOtpCode(code) {
  if (!code || typeof code !== 'string') {
    return { valid: false, error: 'code must be a string' };
  }
  if (!/^\d{6}$/.test(code)) {
    return { valid: false, error: 'code must be exactly 6 digits' };
  }
  return { valid: true };
}

/**
 * Validate device ID
 */
function validateDeviceId(deviceId) {
  if (deviceId === undefined || deviceId === null) {
    return { valid: true }; // Optional field
  }
  if (typeof deviceId !== 'string') {
    return { valid: false, error: 'device_id must be a string' };
  }
  if (deviceId.length > 128) {
    return { valid: false, error: 'device_id must be 128 characters or less' };
  }
  return { valid: true };
}

/**
 * Validate and sanitize device info object
 * Truncates long values instead of rejecting them (safe for informational fields)
 */
function validateDeviceInfo(deviceInfo) {
  if (deviceInfo === undefined || deviceInfo === null) {
    return { valid: true }; // Optional field
  }
  if (typeof deviceInfo !== 'object' || Array.isArray(deviceInfo)) {
    return { valid: false, error: 'device_info must be an object' };
  }

  const maxLength = 100;
  const fields = ['platform', 'model', 'os_version', 'app_version', 'language_code', 'timezone'];
  
  for (const field of fields) {
    if (deviceInfo[field] !== undefined && deviceInfo[field] !== null) {
      if (typeof deviceInfo[field] !== 'string') {
        return { valid: false, error: `device_info.${field} must be a string` };
      }
      // Truncate long values instead of rejecting (safe for informational fields)
      if (deviceInfo[field].length > maxLength) {
        deviceInfo[field] = deviceInfo[field].substring(0, maxLength);
      }
    }
  }

  return { valid: true };
}

/**
 * Validate refresh token
 */
function validateRefreshToken(refreshToken) {
  if (!refreshToken || typeof refreshToken !== 'string') {
    return { valid: false, error: 'refresh_token must be a string' };
  }
  if (refreshToken.length > 1000) {
    return { valid: false, error: 'refresh_token is too long' };
  }
  return { valid: true };
}

/**
 * Validate request body size (prevent DoS)
 */
function validateBodySize(body, maxSize = 10000) {
  const bodyStr = JSON.stringify(body);
  if (bodyStr.length > maxSize) {
    return { valid: false, error: 'Request body too large' };
  }
  return { valid: true };
}

/**
 * Middleware: Validate /auth/request-otp request
 */
function validateRequestOtpBody(req, res, next) {
  const { phone_number } = req.body;

  // Check body size
  const sizeCheck = validateBodySize(req.body, 1000);
  if (!sizeCheck.valid) {
    return res.status(400).json({ error: sizeCheck.error });
  }

  // Validate phone
  if (!phone_number) {
    return res.status(400).json({ error: 'phone_number is required' });
  }

  const phoneCheck = validatePhone(phone_number);
  if (!phoneCheck.valid) {
    return res.status(400).json({ error: phoneCheck.error });
  }

  next();
}

/**
 * Middleware: Validate /auth/verify-otp request
 */
function validateVerifyOtpBody(req, res, next) {
  const { phone_number, code, device_id, device_info } = req.body;

  // Check body size
  const sizeCheck = validateBodySize(req.body, 2000);
  if (!sizeCheck.valid) {
    return res.status(400).json({ error: sizeCheck.error });
  }

  // Validate required fields
  if (!phone_number) {
    return res.status(400).json({ error: 'phone_number is required' });
  }

  if (!code) {
    return res.status(400).json({ error: 'code is required' });
  }

  // Validate each field
  const phoneCheck = validatePhone(phone_number);
  if (!phoneCheck.valid) {
    return res.status(400).json({ error: phoneCheck.error });
  }

  const codeCheck = validateOtpCode(code);
  if (!codeCheck.valid) {
    return res.status(400).json({ error: codeCheck.error });
  }

  const deviceIdCheck = validateDeviceId(device_id);
  if (!deviceIdCheck.valid) {
    return res.status(400).json({ error: deviceIdCheck.error });
  }

  const deviceInfoCheck = validateDeviceInfo(device_info);
  if (!deviceInfoCheck.valid) {
    return res.status(400).json({ error: deviceInfoCheck.error });
  }

  next();
}

/**
 * Middleware: Validate /auth/refresh request
 */
function validateRefreshTokenBody(req, res, next) {
  const { refresh_token } = req.body;

  // Check body size
  const sizeCheck = validateBodySize(req.body, 2000);
  if (!sizeCheck.valid) {
    return res.status(400).json({ error: sizeCheck.error });
  }

  if (!refresh_token) {
    return res.status(400).json({ error: 'refresh_token is required' });
  }

  const tokenCheck = validateRefreshToken(refresh_token);
  if (!tokenCheck.valid) {
    return res.status(400).json({ error: tokenCheck.error });
  }

  next();
}

/**
 * Middleware: Validate /auth/logout request
 */
function validateLogoutBody(req, res, next) {
  const { refresh_token } = req.body;

  // Check body size
  const sizeCheck = validateBodySize(req.body, 2000);
  if (!sizeCheck.valid) {
    return res.status(400).json({ error: sizeCheck.error });
  }

  if (!refresh_token) {
    return res.status(400).json({ error: 'refresh_token is required' });
  }

  const tokenCheck = validateRefreshToken(refresh_token);
  if (!tokenCheck.valid) {
    return res.status(400).json({ error: tokenCheck.error });
  }

  next();
}

module.exports = {
  validateRequestOtpBody,
  validateVerifyOtpBody,
  validateRefreshTokenBody,
  validateLogoutBody,
};

