// In-memory rate limiter for API endpoints
// Tracks request counts per IP within sliding windows

interface RateLimitEntry {
  count: number
  resetAt: number
}

const stores = new Map<string, Map<string, RateLimitEntry>>()

interface RateLimitConfig {
  /** Unique identifier for this limiter (e.g. 'login', 'register') */
  id: string
  /** Maximum requests allowed within the window */
  max: number
  /** Window duration in seconds */
  windowSeconds: number
}

interface RateLimitResult {
  success: boolean
  remaining: number
  resetAt: number
}

function getStore(id: string): Map<string, RateLimitEntry> {
  if (!stores.has(id)) {
    stores.set(id, new Map())
  }
  return stores.get(id)!
}

// Periodic cleanup of expired entries (every 5 minutes)
setInterval(() => {
  const now = Date.now()
  for (const [, store] of stores) {
    for (const [key, entry] of store) {
      if (now > entry.resetAt) {
        store.delete(key)
      }
    }
  }
}, 5 * 60 * 1000)

export function rateLimit(config: RateLimitConfig) {
  const store = getStore(config.id)

  return {
    check(ip: string): RateLimitResult {
      const now = Date.now()
      const key = ip
      const entry = store.get(key)

      // No entry or expired → fresh window
      if (!entry || now > entry.resetAt) {
        store.set(key, {
          count: 1,
          resetAt: now + config.windowSeconds * 1000,
        })
        return { success: true, remaining: config.max - 1, resetAt: now + config.windowSeconds * 1000 }
      }

      // Within window
      entry.count++
      if (entry.count > config.max) {
        return { success: false, remaining: 0, resetAt: entry.resetAt }
      }

      return { success: true, remaining: config.max - entry.count, resetAt: entry.resetAt }
    },
  }
}

// Pre-configured limiters for different endpoints
export const loginLimiter = rateLimit({ id: 'login', max: 10, windowSeconds: 60 * 5 })          // 10 attempts per 5 min
export const registerLimiter = rateLimit({ id: 'register', max: 3, windowSeconds: 60 * 60 })    // 3 per hour
export const forgotPasswordLimiter = rateLimit({ id: 'forgot-pw', max: 3, windowSeconds: 60 * 15 }) // 3 per 15 min
export const resendVerificationLimiter = rateLimit({ id: 'resend-verify', max: 3, windowSeconds: 60 * 15 })
export const contactLimiter = rateLimit({ id: 'contact', max: 5, windowSeconds: 60 * 60 })      // 5 per hour
export const deleteAccountLimiter = rateLimit({ id: 'delete-acct', max: 3, windowSeconds: 60 * 15 })
export const resetPasswordLimiter = rateLimit({ id: 'reset-pw', max: 5, windowSeconds: 60 * 15 })

/** Extract client IP from request headers */
export function getClientIp(req: Request): string {
  const forwarded = req.headers.get('x-forwarded-for')
  if (forwarded) {
    return forwarded.split(',')[0].trim()
  }
  const realIp = req.headers.get('x-real-ip')
  if (realIp) return realIp
  return '127.0.0.1'
}

/** Helper: create a 429 response with retry-after header */
export function rateLimitResponse(resetAt: number) {
  const retryAfter = Math.ceil((resetAt - Date.now()) / 1000)
  const minutes = Math.ceil(retryAfter / 60)
  return new Response(
    JSON.stringify({
      error: `Zu viele Versuche. Bitte warten Sie ${minutes > 1 ? `${minutes} Minuten` : `${retryAfter} Sekunden`} und versuchen es erneut.`,
      retryAfter,
    }),
    {
      status: 429,
      headers: {
        'Content-Type': 'application/json',
        'Retry-After': String(retryAfter),
      },
    }
  )
}
