import { Express } from 'express';
import helmet from 'helmet';
import cors from 'cors';
import rateLimit, { Store, RateLimitRequestHandler } from 'express-rate-limit';
import { Redis } from 'ioredis';
import { env } from '../../main/config/env';
import { RedisRateLimitStore } from '../../infrastructure/cache/redis-rate-limit-store';

const buildRateLimitStore = (windowMs: number, redis?: Redis): Store | undefined => {
  if (!redis) {
    return undefined;
  }
  return new RedisRateLimitStore(redis, windowMs);
};

export const applySecurityMiddleware = (app: Express, redis?: Redis): void => {
  app.use(
    helmet({
      hsts:
        env.NODE_ENV === 'production'
          ? { maxAge: 31_536_000, includeSubDomains: true, preload: true }
          : false,
    }),
  );

  const allowedOrigins = env.ALLOWED_ORIGINS.split(',').map((origin) => origin.trim());
  app.use(
    cors({
      origin: (origin, callback) => {
        if (env.NODE_ENV === 'development' || !origin || allowedOrigins.includes(origin)) {
          callback(null, true);
          return;
        }
        callback(new Error('Not allowed by CORS'));
      },
      credentials: true,
    }),
  );

  const defaultLimiter = rateLimit({
    windowMs: env.RATE_LIMIT_WINDOW_MS,
    max: env.RATE_LIMIT_MAX,
    standardHeaders: true,
    legacyHeaders: false,
    store: buildRateLimitStore(env.RATE_LIMIT_WINDOW_MS, redis),
    keyGenerator: (req) => req.ip ?? 'unknown',
  });

  app.use(defaultLimiter);
};

export const createStrictRateLimiter = (windowMs: number, max: number, redis?: Redis): RateLimitRequestHandler => {
  return rateLimit({
    windowMs,
    max,
    standardHeaders: true,
    legacyHeaders: false,
    store: buildRateLimitStore(windowMs, redis),
    keyGenerator: (req) => req.ip ?? 'unknown',
  });
};
