// Vaultwarden upstream config + header hygiene for the officer-vault sidecar.
//
// HARD RULE (see BITWARDEN_SIDECAR_PROMPT.md): the vault is end-to-end encrypted. Nothing here — or in
// the sidecar that uses it — may decrypt, parse, rewrite, or log request/response BODIES. We only compute
// the upstream base URL and strip hop-by-hop headers. Bytes pass through untouched.

const { VAULTWARDEN_URL } = process.env;

let warnedUnset = false;

/** The Vaultwarden base URL (no trailing slash), or null when unconfigured (the sidecar then 503s). */
export function getVaultBase(): string | null {
  const raw = VAULTWARDEN_URL?.trim();
  if (!raw) {
    if (!warnedUnset) {
      console.warn('[vault] VAULTWARDEN_URL is unset — the sidecar will respond 503 until it is set');
      warnedUnset = true;
    }
    return null;
  }
  return raw.replace(/\/+$/, '');
}

/** The same base as a WebSocket scheme (http→ws, https→wss) for the notifications hub. */
export function getVaultWsBase(): string | null {
  const base = getVaultBase();
  return base ? base.replace(/^http/i, 'ws') : null;
}

// Hop-by-hop headers must not cross a proxy hop (RFC 7230 §6.1). `upgrade` is handled by the dedicated
// WebSocket path; `host` is dropped so the outgoing fetch sets the upstream authority itself. Everything
// else — crucially Authorization, Content-Type, and Bitwarden device headers — is forwarded verbatim.
const HOP_BY_HOP = new Set([
  'connection',
  'keep-alive',
  'proxy-authenticate',
  'proxy-authorization',
  'te',
  'trailer',
  'transfer-encoding',
  'upgrade',
  'host',
]);

/** Copy headers, dropping only hop-by-hop / proxy-* ones. Used for both request and response directions. */
export function stripHopByHop(src: Headers): Headers {
  const out = new Headers();
  src.forEach((value, key) => {
    const k = key.toLowerCase();
    if (HOP_BY_HOP.has(k) || k.startsWith('proxy-')) return;
    out.set(key, value);
  });
  return out;
}

// Redact anything token-shaped from a path+query before it reaches a log line.
const REDACT = /([?&](access_token|refresh_token|code|token)=)[^&]*/gi;
export const redactPath = (pathAndQuery: string): string => pathAndQuery.replace(REDACT, '$1<redacted>');
