// ── Trust proxy configuration ──────────────────────────────────────────────
//
// Real request path for this deployment:
//
//     client → Pangolin → newt tunnel agent ("ptero", separate VM)
//            → this app (its own VM), over the LAN
//
// The hop that actually opens the TCP connection to this app is ptero, so from
// Express's point of view ptero is THE trusted proxy and its LAN IP is the
// right-most/most-recently-added entry to reconcile against. The real client IP
// arrives in X-Forwarded-For. req.ip / req.secure must reflect the real client
// because the rate limiter, exponential backoff, bot-scoring ban, and activity
// log all key on req.ip — so this is a prerequisite for every other control.
//
// Recommended production value: pin TRUST_PROXY to ptero's LAN IP exactly. That
// is stricter than a hop count: Express will only honour XFF on connections that
// actually come from ptero, so nothing else on the LAN can inject a forwarded
// header. See TRUST_PROXY in .env.example for how to set it.
//
// IMPORTANT ASSUMPTION: pinning ptero's IP assumes ptero holds a STATIC IP
// (a DHCP reservation in Omada). If that reservation does not exist, a lease
// change would silently move ptero to a new IP and every XFF would stop being
// trusted — req.ip would collapse to ptero's (new) address for all clients,
// breaking rate limiting/bans. Verify the reservation before relying on this,
// and use DEBUG_TRUST_PROXY (below) to re-check the observed proxy IP without a
// code redeploy if it ever needs to change.
//
// We deliberately DO NOT use a blanket `true`. `true` trusts every hop and takes
// the left-most (client-supplied, spoofable) XFF entry, letting an attacker forge
// their apparent IP to dodge rate limits / bans.
//
// TRUST_PROXY accepts:
//   - unset / ''      -> 1            (single proxy hop fallback)
//   - an integer      -> that many trusted hops (e.g. "2")
//   - "false"         -> false        (no proxy; direct connections only)
//   - "loopback" etc. -> the express preset string, passed through
//   - a CSV of IPs / CIDRs -> that list (e.g. ptero's LAN IP: "10.0.0.42")
//
// `true` is intentionally rejected (coerced to 1) with a warning, so it can't be
// set by accident.

const log = require('./logger')('trustproxy')

function truthyEnv(v) {
  return ['1', 'true', 'yes', 'on'].includes(String(v || '').trim().toLowerCase())
}

const PRESETS = new Set(['loopback', 'linklocal', 'uniquelocal'])

function parseTrustProxy(raw = process.env.TRUST_PROXY) {
  const val = (raw == null ? '' : String(raw)).trim()

  if (val === '') return 1 // default: one hop (Pangolin)
  if (val.toLowerCase() === 'false') return false
  if (val.toLowerCase() === 'true') {
    log.warn('TRUST_PROXY=true is unsafe (trusts spoofable client XFF); using 1 hop instead')
    return 1
  }

  // Pure integer → hop count.
  if (/^\d+$/.test(val)) return Number(val)

  // Single express preset keyword.
  if (PRESETS.has(val.toLowerCase())) return val.toLowerCase()

  // Otherwise treat as a comma-separated list of trusted IPs / CIDRs (and/or
  // preset keywords), which Express accepts as an array.
  const list = val
    .split(',')
    .map((s) => s.trim())
    .filter(Boolean)
  return list.length === 1 ? list[0] : list
}

// Apply the setting to an Express app and log what was chosen.
function applyTrustProxy(app, raw = process.env.TRUST_PROXY) {
  const setting = parseTrustProxy(raw)
  app.set('trust proxy', setting)
  log.info('trust proxy configured', { setting: Array.isArray(setting) ? setting.join(',') : setting })
  return setting
}

// Temporary diagnostic middleware, OFF by default. Set DEBUG_TRUST_PROXY=1 to
// log, per request, the raw peer address and forwarded header alongside the IP
// Express resolved — so the real proxy IP (ptero) can be re-verified in-place
// without a code change if it ever moves. Mounted before the bot guard so it
// still fires for scanner/junk requests (whose source IPs are what we want to
// see). Turn it back off once verified; it is noisy.
function trustProxyDebug(req, res, next) {
  if (truthyEnv(process.env.DEBUG_TRUST_PROXY)) {
    log.info('trust-proxy debug', {
      remoteAddress: req.socket && req.socket.remoteAddress,
      xForwardedFor: req.headers['x-forwarded-for'] || null,
      resolvedIp: req.ip,
      method: req.method,
      path: req.originalUrl,
    })
  }
  return next()
}

module.exports = { parseTrustProxy, applyTrustProxy, trustProxyDebug }
