// plan-chat-proxy-headers.mjs — header handling for host-cp's /api/plan-chat/*
// passthrough proxy (server.mjs). Extracted as pure helpers so the F3 (T9)
// operator-chunk broker-secret contract is unit-testable without booting the
// whole host-cp server.
//
// F3 (T9) boundary: host-cp's /api/plan-chat/* proxy is the TRUSTED operator
// surface (SPA browser → host-cp → plan-chat-service). A WORLD process never
// routes through this proxy — it talks to plan-chat-service directly via
// host.docker.internal. So:
//   - Client-supplied `x-olam-broker-secret` is ALWAYS stripped (a client must
//     not be able to smuggle the operator-chunk authority secret through).
//   - The real secret is injected by the proxy itself (injectBrokerSecret),
//     only when configured, so the operator's own SPA interject is authorised
//     while a world process — which can't present the secret — is rejected by
//     plan-chat-service's gate.

const HOP_BY_HOP = new Set(['host', 'connection', 'content-length']);
const BROKER_SECRET_HEADER = 'x-olam-broker-secret';

/**
 * Build the upstream header map for a /api/plan-chat/* proxy request.
 * Drops hop-by-hop headers AND any client-supplied broker secret (F3).
 *
 * @param {Record<string, string | string[] | undefined>} reqHeaders
 * @returns {Record<string, string>}
 */
export function buildPlanChatProxyHeaders(reqHeaders) {
  const headers = {};
  for (const [k, v] of Object.entries(reqHeaders ?? {})) {
    if (HOP_BY_HOP.has(k)) continue;
    // F3 — never forward a CLIENT-supplied broker secret.
    if (k === BROKER_SECRET_HEADER) continue;
    if (Array.isArray(v)) headers[k] = v.join(', ');
    else if (typeof v === 'string') headers[k] = v;
  }
  return headers;
}

/**
 * Inject the operator-chunk broker secret into the upstream headers when it is
 * configured. No-op when the secret is unset/empty (the gate then runs in its
 * default ungated-but-loud mode). Mutates + returns `headers`.
 *
 * @param {Record<string, string>} headers
 * @param {string | undefined} operatorChunkSecret
 * @returns {Record<string, string>}
 */
export function injectBrokerSecret(headers, operatorChunkSecret) {
  if (typeof operatorChunkSecret === 'string' && operatorChunkSecret.length > 0) {
    headers[BROKER_SECRET_HEADER] = operatorChunkSecret;
  }
  return headers;
}
