'use strict';

import type { Req, Res } from '../types/http';

const { rateLimit, ipKeyGenerator } = require('express-rate-limit');

function makeLimiter(max: number, windowMs: number, message: string): any {
  return rateLimit({
    windowMs,
    max,
    standardHeaders: 'draft-7',
    legacyHeaders: false,
    // Override default handler so the response is always JSON, not HTML
    handler(req: Req, res: Res) {
      res.status(429).json({ error: message });
    },
  });
}

// 10 login attempts per 15 minutes per IP — brute-force protection
const loginLimiter = makeLimiter(
  10,
  15 * 60 * 1000,
  'Too many login attempts. Please try again in 15 minutes.',
);

// 5 FAILED login attempts per 15 minutes per username — layered on the per-IP
// limiter. Successful logins don't count, so legit users are unaffected.
const loginUsernameLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  skipSuccessfulRequests: true,
  keyGenerator: (req: Req) => {
    const username = String(req.body?.username || '')
      .trim()
      .toLowerCase();
    return username ? `user:${username}` : ipKeyGenerator(req);
  },
  handler(req: Req, res: Res) {
    res.status(429).json({
      error: 'Too many failed login attempts for this account. Please try again in 15 minutes.',
    });
  },
});

// 5 password-change attempts per 15 minutes per IP
const passwordLimiter = makeLimiter(
  5,
  15 * 60 * 1000,
  'Too many password change attempts. Please try again in 15 minutes.',
);

// 20 import preview/apply requests per 15 minutes per IP
const importLimiter = makeLimiter(
  20,
  15 * 60 * 1000,
  'Too many import requests. Please try again in 15 minutes.',
);

// 30 export requests per 15 minutes per IP
const exportLimiter = makeLimiter(
  30,
  15 * 60 * 1000,
  'Too many export requests. Please try again in 15 minutes.',
);

// 30 admin mutation actions per 15 minutes per IP (backup/restore/cleanup)
const adminActionLimiter = makeLimiter(
  30,
  15 * 60 * 1000,
  'Too many admin actions. Please try again in 15 minutes.',
);

// 20 OIDC login/callback requests per 15 minutes per IP
const oidcLimiter = makeLimiter(
  20,
  15 * 60 * 1000,
  'Too many authentication requests. Please try again in 15 minutes.',
);

// 5 backup operations per 60 minutes per IP (backup creation, restore, import)
const backupOperationLimiter = makeLimiter(
  5,
  60 * 60 * 1000,
  'Too many backup operations. Please try again in 60 minutes.',
);

// 3 demo data clear operations per 15 minutes per IP
const demoDataLimiter = makeLimiter(
  3,
  15 * 60 * 1000,
  'Too many demo data clear operations. Please try again in 15 minutes.',
);

// 10 sync/backfill requests per 15 minutes per user — prevents SimpleFIN hammering
const syncLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 10,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator: (req: Req) => req.user?.id?.toString() || ipKeyGenerator(req),
  handler(req: Req, res: Res) {
    res.status(429).json({ error: 'Too many sync requests. Please try again in 15 minutes.' });
  },
});

// ── Export all limiters plus reset function ────────────────────────────────────
const allLimiters = [
  loginLimiter,
  loginUsernameLimiter,
  passwordLimiter,
  importLimiter,
  exportLimiter,
  adminActionLimiter,
  oidcLimiter,
  backupOperationLimiter,
  demoDataLimiter,
  syncLimiter,
];

function resetStores(): void {
  for (const limiter of allLimiters) {
    if (limiter.store.reset) {
      limiter.store.reset();
    }
  }
}

module.exports = {
  loginLimiter,
  loginUsernameLimiter,
  passwordLimiter,
  importLimiter,
  exportLimiter,
  adminActionLimiter,
  oidcLimiter,
  backupOperationLimiter,
  demoDataLimiter,
  syncLimiter,
  resetStores,
};
