import rateLimit, { ipKeyGenerator } from 'express-rate-limit'
import type { Request } from 'express'
import { verifyAnyActorToken } from '../security/tokens'
import { getSessionCookieName } from '../security/sessionCookies'


const SESSION_COOKIE_NAMES = [
  getSessionCookieName('admin'),
  getSessionCookieName('employee'),
  getSessionCookieName('renter'),
]

function readCookie(cookieHeader: string | undefined, name: string): string | null {
  if (!cookieHeader) return null

  for (const chunk of cookieHeader.split(';')) {
    const [rawName, ...rawValue] = chunk.trim().split('=')
    if (rawName === name) return decodeURIComponent(rawValue.join('='))
  }

  return null
}

function getBearerToken(req: Request): string | null {
  const authHeader = req.headers.authorization
  if (!authHeader?.startsWith('Bearer ')) return null
  const token = authHeader.slice(7).trim()
  return token || null
}

function getRequestToken(req: Request): string | null {
  const cookieHeader = req.headers.cookie
  for (const name of SESSION_COOKIE_NAMES) {
    const token = readCookie(cookieHeader, name)
    if (token) return token
  }

  return getBearerToken(req)
}

function getAuthenticatedActorKey(req: Request): string | null {
  const token = getRequestToken(req)
  if (!token) return null

  try {
    const payload = verifyAnyActorToken(token)
    return `${payload.type}:${payload.sub}`
  } catch {
    return null
  }
}

// req.ip is already the real client IP when app.set('trust proxy', 1) is configured
const getClientIpKey = (req: Request) => ipKeyGenerator(req.ip ?? '')

// Strict limiter for auth endpoints — prevents brute-force and credential stuffing.
// Successful requests (e.g. GET /me profile reads) are skipped so only failed
// attempts count toward the cap.
export const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 20,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  skipSuccessfulRequests: true,
  keyGenerator: (req) => getClientIpKey(req),
  message: { error: 'too_many_requests', message: 'Too many attempts, please try again later', statusCode: 429 },
})

// Standard limiter for general authenticated API endpoints
export const apiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 120,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator: (req) => {
    const ip = getClientIpKey(req)
    const actorKey = getAuthenticatedActorKey(req)
    const companyId = (req as any).companyId ?? ''
    const renterId = (req as any).renterId ?? ''
    return `${ip}:${actorKey || companyId || renterId || 'anonymous'}`
  },
  message: { error: 'too_many_requests', message: 'Rate limit exceeded', statusCode: 429 },
})

// Limiter for public carplace and site endpoints (no auth)
export const publicLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 60,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator: (req) => getClientIpKey(req),
  message: { error: 'too_many_requests', message: 'Rate limit exceeded', statusCode: 429 },
})

// Tight limiter for admin endpoints
export const adminLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator: (req) => {
    const ip = getClientIpKey(req)
    return `${ip}:${getAuthenticatedActorKey(req) || 'anonymous'}`
  },
  message: { error: 'too_many_requests', message: 'Too many admin requests', statusCode: 429 },
})


// Applied after authentication so limits can include actor identity rather than
// pretending every employee behind the same NAT is the same organism.
export const actorLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 240,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  keyGenerator: (req) => {
    const ip = getClientIpKey(req)
    const actorKey = getAuthenticatedActorKey(req)
    const companyId = (req as any).companyId ?? ''
    const employeeId = (req as any).employee?.id ?? ''
    const renterId = (req as any).renterId ?? ''
    const adminId = (req as any).admin?.id ?? ''
    return `${ip}:${companyId}:${actorKey || employeeId || renterId || adminId || 'anonymous'}`
  },
  message: { error: 'too_many_requests', message: 'Authenticated rate limit exceeded', statusCode: 429 },
})
