/**
 * 安全中间件
 * @file security.js
 * @description 处理安全相关的中间件
 */
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const { body, validationResult } = require('express-validator');

/**
 * API请求频率限制
 */
const apiRateLimiter = rateLimit({
  windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15分钟
  max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100, // 限制每个IP 15分钟内最多100个请求
  message: {
    success: false,
    message: '请求过于频繁，请稍后再试'
  },
  standardHeaders: true,
  legacyHeaders: false,
  handler: (req, res) => {
    res.status(429).json({
      success: false,
      message: '请求过于频繁，请稍后再试'
    });
  }
});

/**
 * 登录请求频率限制（更严格）
 */
const loginRateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 5, // 限制每个IP 15分钟内最多5次登录尝试
  message: {
    success: false,
    message: '登录尝试次数过多，请15分钟后再试'
  },
  skipSuccessfulRequests: true,
  handler: (req, res) => {
    res.status(429).json({
      success: false,
      message: '登录尝试次数过多，请15分钟后再试'
    });
  }
});

/**
 * 安全头部设置
 */
const securityHeaders = helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
      connectSrc: ["'self'"],
      fontSrc: ["'self'"],
      objectSrc: ["'none'"],
      mediaSrc: ["'self'"],
      frameSrc: ["'none'"]
    }
  },
  crossOriginEmbedderPolicy: false
});

/**
 * 输入数据清理
 */
const inputSanitizer = (req, res, next) => {
  // 清理请求体中的危险字符
  const sanitizeObject = (obj) => {
    if (typeof obj !== 'object' || obj === null) return obj;
    
    for (const key in obj) {
      if (typeof obj[key] === 'string') {
        // 移除潜在的XSS攻击字符
        obj[key] = obj[key]
          .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
          .replace(/javascript:/gi, '')
          .replace(/on\w+\s*=/gi, '');
      } else if (typeof obj[key] === 'object') {
        sanitizeObject(obj[key]);
      }
    }
  };

  if (req.body) sanitizeObject(req.body);
  if (req.query) sanitizeObject(req.query);
  if (req.params) sanitizeObject(req.params);

  next();
};

/**
 * 会话超时检查
 */
const sessionTimeoutCheck = (req, res, next) => {
  if (req.user && req.user.last_login) {
    const lastLogin = new Date(req.user.last_login);
    const now = new Date();
    const timeout = 24 * 60 * 60 * 1000; // 24小时

    if (now - lastLogin > timeout) {
      return res.status(401).json({
        success: false,
        message: '会话已超时，请重新登录'
      });
    }
  }
  next();
};

/**
 * 验证错误处理中间件
 */
const handleValidationErrors = (req, res, next) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({
      success: false,
      message: '输入数据验证失败',
      errors: errors.array()
    });
  }
  next();
};

/**
 * 银行账户验证规则
 */
const validateAccountNumber = [
  body('account_number')
    .isLength({ min: 16, max: 20 })
    .withMessage('账户号码长度必须在16-20位之间')
    .matches(/^\d+$/)
    .withMessage('账户号码只能包含数字'),
  handleValidationErrors
];

/**
 * 金额验证规则
 */
const validateAmount = [
  body('amount')
    .isFloat({ min: 0.01 })
    .withMessage('金额必须大于0')
    .custom((value) => {
      // 检查金额精度（最多2位小数）
      if (value.toString().split('.')[1] && value.toString().split('.')[1].length > 2) {
        throw new Error('金额最多支持2位小数');
      }
      return true;
    }),
  handleValidationErrors
];

/**
 * 身份证号验证规则
 */
const validateIdCard = [
  body('id_card')
    .matches(/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/)
    .withMessage('身份证号码格式不正确'),
  handleValidationErrors
];

/**
 * 手机号验证规则
 */
const validatePhone = [
  body('phone')
    .matches(/^1[3-9]\d{9}$/)
    .withMessage('手机号码格式不正确'),
  handleValidationErrors
];

/**
 * 密码验证规则
 */
const validatePassword = [
  body('password')
    .isLength({ min: 6, max: 20 })
    .withMessage('密码长度必须在6-20位之间')
    .matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
    .withMessage('密码必须包含大小写字母和数字'),
  handleValidationErrors
];

/**
 * 防止SQL注入的查询参数验证
 */
const validateQueryParams = (req, res, next) => {
  const dangerousPatterns = [
    /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|UNION|SCRIPT)\b)/i,
    /(--|\/\*|\*\/|xp_|sp_)/i,
    /(\bOR\b|\bAND\b).*(\bOR\b|\bAND\b)/i
  ];

  const checkObject = (obj) => {
    for (const key in obj) {
      if (typeof obj[key] === 'string') {
        for (const pattern of dangerousPatterns) {
          if (pattern.test(obj[key])) {
            return res.status(400).json({
              success: false,
              message: '检测到潜在的安全威胁'
            });
          }
        }
      } else if (typeof obj[key] === 'object' && obj[key] !== null) {
        checkObject(obj[key]);
      }
    }
  };

  checkObject(req.query);
  checkObject(req.body);
  checkObject(req.params);

  next();
};

module.exports = {
  apiRateLimiter,
  loginRateLimiter,
  securityHeaders,
  inputSanitizer,
  sessionTimeoutCheck,
  handleValidationErrors,
  validateAccountNumber,
  validateAmount,
  validateIdCard,
  validatePhone,
  validatePassword,
  validateQueryParams
};