// lib/hail/redaction.js — shared restricted-value redaction for HAIL synthesis.
//
// Defense-in-depth used by every HAIL synthesizer (diagnostic, blueprint): no
// matter what an LLM returns — or what a caller injects — a `restricted` answer
// value must never be echoed verbatim into a persisted record or artifact. The
// engine projection (interview.js) already masks restricted for cloud engines;
// this scrub additionally protects the LOCAL `ollama` path, where restricted is
// intentionally unmasked at the projection layer, and any injected payload.
//
// Pure except for a single read query; no writes.

import { getDb } from '../db.js';

// The raw restricted answer values for an engagement — read directly (NOT via
// the engine projection, which masks them) so we know exactly what must never
// appear in output. `refused` answers carry no stored value, so nothing to scrub.
export function getRestrictedValues(engagement_id) {
  if (!engagement_id) return [];
  return getDb()
    .prepare("SELECT answer FROM hail_interview_responses WHERE engagement_id = ? AND sensitivity = 'restricted' AND answer IS NOT NULL")
    .all(engagement_id)
    .map((r) => r.answer);
}

// Deep-walk `payload`, replacing any string occurrence of a known restricted
// value with a redaction marker. Returns a sanitized clone (input untouched).
export function scrubRestricted(payload, restrictedValues) {
  if (!restrictedValues || !restrictedValues.length) return payload;
  const needles = restrictedValues.filter((v) => typeof v === 'string' && v.trim().length >= 3);
  if (!needles.length) return payload;
  const replace = (s) => {
    let out = s;
    for (const n of needles) {
      if (out.includes(n)) out = out.split(n).join('[restricted: withheld]');
    }
    return out;
  };
  const walk = (v) => {
    if (typeof v === 'string') return replace(v);
    if (Array.isArray(v)) return v.map(walk);
    if (v && typeof v === 'object') {
      const o = {};
      for (const [k, val] of Object.entries(v)) o[k] = walk(val);
      return o;
    }
    return v;
  };
  return walk(payload);
}
