/**
 * lib/share-secret.js — Shared HMAC secret + helpers for all share links.
 *
 * Extracted from lib/artifact-acl.js so artifact share links AND space share
 * links derive from the SAME MADARX_SHARE_LINK_SECRET and the SAME public-route
 * IP rate limiter. Token design (RD-3):
 *   1. 32 random bytes, base64url → visible token in the URL.
 *   2. HMAC-SHA256(token, secret) → stored token_hmac (raw token never stored).
 *   3. Verify: recompute HMAC, compare with timingSafeEqual.
 *
 * Secret priority: env MADARX_SHARE_LINK_SECRET → secrets vault → auto-generated
 * + persisted to the vault (with a loud warning).
 */

import { randomBytes, createHmac, timingSafeEqual } from 'node:crypto';

let _shareSecret = null; // resolved lazily on first use

export async function resolveShareSecret() {
  if (_shareSecret) return _shareSecret;

  if (process.env.MADARX_SHARE_LINK_SECRET) {
    _shareSecret = process.env.MADARX_SHARE_LINK_SECRET;
    return _shareSecret;
  }

  try {
    const { getSecret, setSecret } = await import('./secrets.js');
    const vaultValue = await getSecret('MADARX_SHARE_LINK_SECRET', { scope: 'global' });
    if (vaultValue) {
      _shareSecret = vaultValue;
      return _shareSecret;
    }

    const generated = randomBytes(32).toString('hex');
    console.warn(
      '[share-secret] WARNING: MADARX_SHARE_LINK_SECRET is not set. ' +
      'A random key has been generated and stored in the secrets vault. ' +
      'Set MADARX_SHARE_LINK_SECRET in your environment before deploying to production — ' +
      'losing this key invalidates all existing share links.'
    );
    await setSecret('MADARX_SHARE_LINK_SECRET', generated, { scope: 'global', source: 'auto_generated' });
    _shareSecret = generated;
    return _shareSecret;
  } catch (err) {
    console.warn(
      '[share-secret] WARNING: Could not access secrets vault for MADARX_SHARE_LINK_SECRET. ' +
      'Using an ephemeral key — share links will break on restart. Error: ' + err.message
    );
    _shareSecret = randomBytes(32).toString('hex');
    return _shareSecret;
  }
}

export function computeHmac(token, secret) {
  return createHmac('sha256', secret).update(token).digest('hex');
}

export function hmacMatch(candidate, stored) {
  const a = Buffer.from(candidate, 'hex');
  const b = Buffer.from(stored, 'hex');
  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b);
}

// ── In-memory IP rate limiter for the public share routes ─────────────────────
// 100 requests/hour per IP. Process-local (madarX is single-process local-first).

const _ipRateMap = new Map();
const IP_RATE_LIMIT = 100;
const IP_RATE_WINDOW_MS = 60 * 60 * 1000;

export function checkIpRateLimit(ip) {
  if (!ip) return { ok: true };
  const now = Date.now();
  const entry = _ipRateMap.get(ip);
  if (!entry || now - entry.windowStart >= IP_RATE_WINDOW_MS) {
    _ipRateMap.set(ip, { count: 1, windowStart: now });
    return { ok: true };
  }
  if (entry.count >= IP_RATE_LIMIT) {
    return { ok: false, retryAfterMs: IP_RATE_WINDOW_MS - (now - entry.windowStart) };
  }
  entry.count += 1;
  return { ok: true };
}
