/**
 * Orchestrator-level verification for Task 1 (Sanitize before storing).
 * Tests the real implementation in src/lib/ingest/sanitize.ts (zod schemas +
 * sanitizers) and the CSV formula-injection guard in
 * src/lib/export/csvGenerator.ts (neutralizeFormulaPrefix).
 *
 * Run:  node --experimental-loader ./scripts/cors-resolve-hook.mjs scripts/verify_sanitize_orchestrator.mjs
 */
import { sanitizeText, sanitizeMultilineText, sanitizeReceiptBatch, sanitizeReceipt, StoredReceiptSchema } from "../src/lib/ingest/sanitize.ts";
import { neutralizeFormulaPrefix } from "../src/lib/export/csvGenerator.ts";

let failed = 0;
let checks = 0;
function expect(cond, label) {
  checks++;
  if (!cond) { failed++; console.error("  FAIL:", label); }
  else console.log("  ok  ", label);
}

console.log("[1] sanitizeText strips markup + control chars");
const dirty = `<script>alert(1)</script>Händler <b>GmbH</b>\u0000\u0007`;
const clean = sanitizeText(dirty, 200);
expect(!clean.includes("<") && !clean.includes(">"), "no < > remain");
expect(!clean.includes("\u0000") && !clean.includes("\u0007"), "control chars stripped");
expect(clean.includes("Händler GmbH"), "text preserved");
expect(sanitizeText("a\u00a0b  c", 100) === "a b c", "whitespace collapsed");

console.log("[2] multiline OCR keeps line layout, strips markup");
const ocr = "Zeile1\nZeile2<img onerror=alert(1)>\tZeile3";
const ocrClean = sanitizeMultilineText(ocr, 50_000);
expect(ocrClean.includes("\n"), "newlines survive");
expect(!ocrClean.includes("<"), "markup stripped");
expect(ocrClean.includes("Zeile3"), "tab survived");

console.log("[3] length caps");
expect(sanitizeText("x".repeat(500), 64).length === 64, "capped at limit");

console.log("[4] sanitizeReceiptBatch — malicious receipt payload");
const evil = {
  id: "r1<script>",
  merchant: { name: '=HYPERLINK("http://evil","x")', address: null, taxId: null, confidence: 1 },
  date: { isoDate: "2026-08-15", time: null, confidence: 1 },
  documentType: "KASSENBON",
  receiptNumber: "+cmd|' /C calc'!A0",
  currency: "EUR",
  totalAmount: { value: 12.5, confidence: 1 },
  netAmount: 10.5,
  taxBreakdown: [{ ratePercent: 19, taxAmount: 2, netAmount: 10.5 }],
  lineItems: [{ description: "<b>Cola</b>", quantity: 2, price: 2.5, unitPrice: 1.25, taxRate: 19 }],
  suggestedCategory: "Sonstiges<script>",
  validation: { isMathValid: true, isDuplicateSuspected: false, needsUserReview: false, reviewField: "none", reviewReason: null },
  rawText: "OCR <img onerror=1> line\n2",
  paymentMethod: "CASH",
  createdAt: "2026-08-15T10:00:00.000Z",
};
const batch = sanitizeReceiptBatch([evil]);
expect(batch.ok === true, "malicious-but-structurally-valid payload accepted (sanitized)");
if (batch.ok && batch.receipts) {
  const r = batch.receipts[0];
  expect(!r.merchant.name.includes("<") && !r.merchant.name.includes(">"), "merchant markup stripped");
  expect(!r.suggestedCategory.includes("<script>"), "category markup stripped");
  expect(!r.rawText.includes("<"), "rawText markup stripped");
  expect(r.currency === "EUR", "currency normalized");
  expect(r.id === "r1", "id sanitized (markup tag removed)");
}

console.log("[5] sanitizeReceiptBatch — structural rejection");
expect(sanitizeReceiptBatch(null).ok === false, "null payload rejected");
expect(sanitizeReceiptBatch({}).ok === false, "empty object rejected");
expect(sanitizeReceiptBatch([]).ok === false, "empty array rejected");
expect(sanitizeReceiptBatch([{ id: 42 }]).ok === false, "non-string id rejected");
expect(sanitizeReceiptBatch([{ id: "x", merchant: { name: 5 } }]).ok === false, "non-string merchant name rejected");
expect(sanitizeReceiptBatch([{ id: "x", currency: "EURO" }]).ok === false, "bad currency rejected");
expect(sanitizeReceiptBatch([{ id: "x", totalAmount: { value: NaN } }]).ok === false, "NaN amount rejected");
const tooMany = Array.from({ length: 501 }, (_, i) => ({ id: `r${i}`, currency: "EUR", totalAmount: { value: 1 } }));
expect(sanitizeReceiptBatch(tooMany).ok === false, "501 receipts rejected");
expect(sanitizeReceiptBatch(tooMany).error.includes("Too many"), "batch-size error message");

console.log("[6] sanitizeReceipt single variant");
expect(sanitizeReceipt(evil) !== null, "valid single receipt sanitized");
expect(sanitizeReceipt({ id: "x" }) === null, "invalid single receipt → null");

console.log("[7] CSV formula injection — neutralizeFormulaPrefix");
expect(neutralizeFormulaPrefix('=HYPERLINK("http://evil","x")') === "'=HYPERLINK(\"http://evil\",\"x\")", "= prefix neutralized");
expect(neutralizeFormulaPrefix('+cmd|\' /C calc\'!A0') === "'+cmd|' /C calc'!A0", "+ non-number neutralized");
expect(neutralizeFormulaPrefix('@SUM(1+1)') === "'@SUM(1+1)", "@ neutralized");
expect(neutralizeFormulaPrefix('\t=1') === "'\t=1", "tab neutralized");
expect(neutralizeFormulaPrefix('-5,00') === "-5,00", "negative number literal untouched (credit note)");
expect(neutralizeFormulaPrefix('+1,25') === "+1,25", "positive number literal untouched");
expect(neutralizeFormulaPrefix('-SUM(1+1)') === "'-SUM(1+1)", "- non-number neutralized");
expect(neutralizeFormulaPrefix('Rewe Markt') === "Rewe Markt", "normal text untouched");

console.log(`\n${checks} checks, ${failed} failure(s)`);
if (failed > 0) process.exit(1);
console.log("SANITIZE VERIFICATION PASSED");
