// Redaction pass applied ONLY at the ft-index seam (the queryable KB), never at journal
// write time — the journal at ~/.local/state/overdeck/prompts/prompts.jsonl keeps the
// owner's verbatim prompt (0600, private); the index a wider set of agents will query
// must not carry credential values.
//
// Coverage: recognizable secret SHAPES only — prefixed tokens (AWS/GitHub/Slack/Stripe/
// OpenAI/Anthropic/generic Bearer), PEM private key blocks, JWTs, and key=value /
// Authorization-header assignments whose value looks like a secret. NOT covered: secrets
// with no recognizable shape (a random password with no prefix, a raw high-entropy string
// pasted with no surrounding "key="/"token=" cue) — those pass through unless a human or a
// more capable secret-shape scanner flags them.

const RULES = [
  { name: "aws-access-key", re: /\bAKIA[0-9A-Z]{16}\b/g },
  { name: "github-token", re: /\bgh[oprsu]_[A-Za-z0-9]{20,}\b/g },
  { name: "github-pat", re: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g },
  { name: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
  { name: "stripe-key", re: /\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g },
  { name: "openai-key", re: /\bsk-[A-Za-z0-9]{20,}\b/g },
  { name: "anthropic-key", re: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g },
  { name: "pem-private-key", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g },
  { name: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
  { name: "authorization-header", re: /\b(Authorization\s*:\s*Bearer)\s+\S+/gi, group: 1 },
  {
    name: "key-value-secret",
    re: /\b((?:api[_-]?key|apikey|secret|password|passwd|token|access[_-]?token|private[_-]?key)\s*[:=]\s*)(["']?)([^\s"',;]{6,})\2/gi,
    group: 1,
  },
];

export function redact(text) {
  if (typeof text !== "string" || !text) return { text: text ?? "", redactedKinds: [] };
  let out = text;
  const kinds = new Set();
  for (const rule of RULES) {
    out = out.replace(rule.re, (match, ...rest) => {
      kinds.add(rule.name);
      if (rule.group) {
        const captured = rest[rule.group - 1];
        return `${captured}[REDACTED:${rule.name}]`;
      }
      return `[REDACTED:${rule.name}]`;
    });
  }
  return { text: out, redactedKinds: [...kinds] };
}
