/**
 * Tier 2: Boundary & Corner Cases Test Suite
 * Minimum 75 boundary, edge case, and stress tests (>=5 tests per feature area).
 */

import { describe, test, it, expect } from "./runner";
import {
  ReceiptExtractionSchema,
  ReceiptData,
  ProcessedReceipt,
} from "../../src/lib/schema/receipt";
import { validateReceiptMath } from "../../src/lib/ai/mathValidator";
import { generateDualSheetExcel } from "../../src/lib/export/excelGenerator";
import { generateAccountingCsv } from "../../src/lib/export/csvGenerator";
import { processReceiptImage } from "../../src/lib/image/processor";
import fs from "fs";
import path from "path";
import ExcelJS from "exceljs";

function createBoundaryReceipt(overrides: Partial<ProcessedReceipt> = {}): ProcessedReceipt {
  return {
    id: `b-rcpt-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`,
    merchant: {
      name: "Boundary Merchant",
      address: null,
      taxId: null,
      confidence: 1.0,
    },
    date: {
      isoDate: "2026-08-15",
      time: null,
      confidence: 1.0,
    },
    documentType: "KASSENBON",
    receiptNumber: "BOUND-001",
    currency: "EUR",
    totalAmount: {
      value: 10.0,
      confidence: 1.0,
    },
    netAmount: 8.4,
    taxBreakdown: [
      {
        ratePercent: 19,
        taxAmount: 1.6,
        netAmount: 8.4,
      },
    ],
    lineItems: [
      {
        description: "Test Item",
        quantity: 1,
        price: 10.0,
        taxRate: 19,
      },
    ],
    suggestedCategory: "Sonstiges",
    validation: {
      isMathValid: true,
      isDuplicateSuspected: false,
      needsUserReview: false,
      reviewField: "none",
      reviewReason: null,
    },
    imageHash: "hash-bound-01",
    originalFileName: "boundary.jpg",
    fileSizeBytes: 1000,
    createdAt: "2026-08-15T12:00:00.000Z",
    updatedAt: "2026-08-15T12:00:00.000Z",
    status: "ready",
    ...overrides,
  };
}

describe("Tier 2: Boundary 1 — 0.00€ Zero-Value Receipts & Nil Tax Cases", () => {
  test("B1.1 should validate 0.00€ receipt with 0.00€ net and empty tax breakdown", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 0.0, confidence: 1.0 },
      netAmount: 0.0,
      taxBreakdown: [{ ratePercent: 0, taxAmount: 0.0, netAmount: 0.0 }],
      lineItems: [{ description: "Free Promotion", quantity: 1, price: 0.0, taxRate: 0 }],
    });

    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
    expect(val.needsUserReview).toBe(false);
    expect(val.calculatedGross).toBe(0.0);
  });

  test("B1.2 should format 0.00€ in the accounting CSV correctly as '0,00'", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 0.0, confidence: 1.0 },
      netAmount: 0.0,
      taxBreakdown: [],
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"0,00"');
  });

  test("B1.3 should generate Excel workbook for 0.00€ receipt without division errors", async () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 0.0, confidence: 1.0 },
      netAmount: 0.0,
      taxBreakdown: [],
      lineItems: [],
    });
    const buf = await generateDualSheetExcel([r]);
    expect(buf.length).toBeGreaterThan(500);
  });

  test("B1.4 should handle 0-quantity line items", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 0.0, confidence: 1.0 },
      netAmount: 0.0,
      lineItems: [{ description: "Zero Item", quantity: 0, price: 0.0, taxRate: 0 }],
    });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(0.0);
  });

  test("B1.5 should accept 0.00€ values in Zod schema", () => {
    const data = createBoundaryReceipt({
      totalAmount: { value: 0.0, confidence: 1.0 },
      netAmount: 0.0,
    });
    const res = ReceiptExtractionSchema.safeParse(data);
    expect(res.success).toBe(true);
  });
});

describe("Tier 2: Boundary 2 — Commercial Rounding Tolerances (0.01€, 0.02€, 0.03€ vs >0.03€)", () => {
  test("B2.1 should accept 0.01€ rounding delta (within 0.03€ epsilon)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 11.91, confidence: 1.0 },
      netAmount: 10.0,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 1.9, netAmount: 10.0 }], // 10.00 + 1.90 = 11.90 (diff 0.01)
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B2.2 should accept 0.02€ rounding delta (within 0.03€ epsilon)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 11.92, confidence: 1.0 },
      netAmount: 10.0,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 1.9, netAmount: 10.0 }], // diff 0.02
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B2.3 should accept exactly 0.03€ boundary rounding delta", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 11.93, confidence: 1.0 },
      netAmount: 10.0,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 1.9, netAmount: 10.0 }], // diff 0.03
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B2.4 should flag discrepancy when delta exceeds 0.03€ (e.g. 0.04€)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 11.94, confidence: 1.0 },
      netAmount: 10.0,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 1.9, netAmount: 10.0 }], // diff 0.04 > 0.03
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(false);
    expect(val.needsUserReview).toBe(true);
  });

  test("B2.5 should handle fractional line item prices sum accumulating within epsilon", () => {
    // 3 items at 3.33€ = 9.99€ vs gross 10.00€ (diff 0.01€)
    const r = createBoundaryReceipt({
      totalAmount: { value: 10.0, confidence: 1.0 },
      netAmount: 8.4,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 1.6, netAmount: 8.4 }],
      lineItems: [
        { description: "Item 1", quantity: 1, price: 3.33, taxRate: 19 },
        { description: "Item 2", quantity: 1, price: 3.33, taxRate: 19 },
        { description: "Item 3", quantity: 1, price: 3.33, taxRate: 19 },
      ],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });
});

describe("Tier 2: Boundary 3 — Multi-Tax Splits & Exotic Tax Rates", () => {
  test("B3.1 should validate 7% and 19% split accurately", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 126.0, confidence: 1.0 },
      netAmount: 115.97,
      taxBreakdown: [
        { ratePercent: 7, taxAmount: 7.0, netAmount: 100.0 }, // 107.00
        { ratePercent: 19, taxAmount: 3.03, netAmount: 15.97 }, // 19.00
      ],
      lineItems: [
        { description: "Food item", quantity: 1, price: 107.0, taxRate: 7 },
        { description: "Non-food item", quantity: 1, price: 19.0, taxRate: 19 },
      ],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B3.2 should validate 0% tax-free receipts (e.g. postage, medical, sovereign fees)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 50.0, confidence: 1.0 },
      netAmount: 50.0,
      taxBreakdown: [{ ratePercent: 0, taxAmount: 0.0, netAmount: 50.0 }],
      lineItems: [{ description: "Postage Stamps", quantity: 1, price: 50.0, taxRate: 0 }],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
    expect(val.calculatedTaxSum).toBe(0.0);
  });

  test("B3.3 should accept international VAT rate like Swiss 8.1%", () => {
    const r = createBoundaryReceipt({
      currency: "CHF",
      totalAmount: { value: 108.1, confidence: 1.0 },
      netAmount: 100.0,
      taxBreakdown: [{ ratePercent: 8.1, taxAmount: 8.1, netAmount: 100.0 }],
      lineItems: [{ description: "Swiss Hotel", quantity: 1, price: 108.1, taxRate: 8.1 }],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B3.4 should accept UK standard 20% VAT", () => {
    const r = createBoundaryReceipt({
      currency: "GBP",
      totalAmount: { value: 120.0, confidence: 1.0 },
      netAmount: 100.0,
      taxBreakdown: [{ ratePercent: 20, taxAmount: 20.0, netAmount: 100.0 }],
      lineItems: [{ description: "London Transport", quantity: 1, price: 120.0, taxRate: 20 }],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B3.5 should handle receipts with 4 separate tax baskets", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 100.0, confidence: 1.0 },
      netAmount: 88.0,
      taxBreakdown: [
        { ratePercent: 19, taxAmount: 4.75, netAmount: 25.0 },
        { ratePercent: 7, taxAmount: 1.75, netAmount: 25.0 },
        { ratePercent: 5, taxAmount: 1.25, netAmount: 25.0 },
        { ratePercent: 0, taxAmount: 0.0, netAmount: 13.0 },
      ],
      lineItems: [],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(false); // 88 + 7.75 = 95.75 != 100 -> correctly flagged
  });
});

describe("Tier 2: Boundary 4 — Negative Line Items, Discounts & Bottle Deposits (Pfand)", () => {
  test("B4.1 should validate receipt with negative bottle deposit (Pfand -0.25€)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 9.75, confidence: 1.0 },
      netAmount: 8.19,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 1.56, netAmount: 8.19 }],
      lineItems: [
        { description: "Getränk Kiste", quantity: 1, price: 10.0, taxRate: 19 },
        { description: "Leergut Rückgabe (Pfand)", quantity: 1, price: -0.25, taxRate: 19 },
      ],
    });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(9.75);
    expect(val.isMathValid).toBe(true);
  });

  test("B4.2 should validate receipt with commercial discount voucher (-10.00€)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 40.0, confidence: 1.0 },
      netAmount: 33.61,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 6.39, netAmount: 33.61 }],
      lineItems: [
        { description: "Wareneinkauf", quantity: 1, price: 50.0, taxRate: 19 },
        { description: "Aktionsgutschein Rabatt", quantity: 1, price: -10.0, taxRate: 19 },
      ],
    });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(40.0);
    expect(val.isMathValid).toBe(true);
  });

  test("B4.3 should export negative line items into Excel Sheet 2 without syntax errors", async () => {
    const r = createBoundaryReceipt({
      lineItems: [
        { description: "Item 1", quantity: 1, price: 20.0, taxRate: 19 },
        { description: "Pfand", quantity: 1, price: -3.5, taxRate: 19 },
      ],
    });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s2 = wb.getWorksheet("Einzelpositionen Detail");
    expect(s2?.rowCount).toBeGreaterThanOrEqual(3);
  });

  test("B4.4 should handle multiple Pfand return lines", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 15.0, confidence: 1.0 },
      netAmount: 12.61,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 2.39, netAmount: 12.61 }],
      lineItems: [
        { description: "Mineralwasser 12x", quantity: 1, price: 21.6, taxRate: 19 },
        { description: "Pfand Kiste", quantity: 1, price: -3.3, taxRate: 19 },
        { description: "Pfand Flaschen", quantity: 1, price: -3.3, taxRate: 19 },
      ],
    });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(15.0);
  });

  test("B4.5 should format negative values in the accounting CSV properly", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: -15.0, confidence: 1.0 },
      netAmount: -12.61,
      taxBreakdown: [{ ratePercent: 19, taxAmount: -2.39, netAmount: -12.61 }],
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"-15,00"');
  });
});

describe("Tier 2: Boundary 5 — Missing Net Amounts & Auto-Reconciliation", () => {
  test("B5.1 should handle null netAmount when single 19% tax breakdown exists", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 119.0, confidence: 1.0 },
      netAmount: null,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 19.0, netAmount: null }],
    });
    const val = validateReceiptMath(r);
    // When net is null, net check doesn't fail
    expect(val.isMathValid).toBe(true);
  });

  test("B5.2 Excel export should compute fallback net (gross - taxes) when netAmount is null", async () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 100.0, confidence: 1.0 },
      netAmount: null,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 15.97, netAmount: null }],
    });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s1 = wb.getWorksheet("Belegübersicht");
    const netCell = s1?.getRow(2).getCell(7);
    expect(netCell?.value).toBeCloseTo(84.03, 2);
  });

  test("B5.3 Accounting CSV should compute fallback net when netAmount is null", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 100.0, confidence: 1.0 },
      netAmount: null,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 15.97, netAmount: null }],
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"84,03"');
  });

  test("B5.4 should handle missing net on multi-tax receipt", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 100.0, confidence: 1.0 },
      netAmount: null,
      taxBreakdown: [
        { ratePercent: 7, taxAmount: 3.5, netAmount: null },
        { ratePercent: 19, taxAmount: 9.5, netAmount: null },
      ],
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"87,00"'); // 100 - (3.5 + 9.5) = 87.00
  });

  test("B5.5 should handle empty taxBreakdown with null netAmount", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 50.0, confidence: 1.0 },
      netAmount: null,
      taxBreakdown: [],
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"50,00"');
  });
});

describe("Tier 2: Boundary 6 — Foreign Currencies & Unicode Characters", () => {
  test("B6.1 should parse US Dollar (USD) currency code", () => {
    const r = createBoundaryReceipt({ currency: "USD", totalAmount: { value: 49.99, confidence: 1 } });
    expect(r.currency).toBe("USD");
  });

  test("B6.2 should parse British Pound (GBP) currency code", () => {
    const r = createBoundaryReceipt({ currency: "GBP", totalAmount: { value: 25.5, confidence: 1 } });
    expect(r.currency).toBe("GBP");
  });

  test("B6.3 should parse Swiss Franc (CHF) currency code", () => {
    const r = createBoundaryReceipt({ currency: "CHF", totalAmount: { value: 85.0, confidence: 1 } });
    expect(r.currency).toBe("CHF");
  });

  test("B6.4 should preserve Japanese characters in merchant name", () => {
    const r = createBoundaryReceipt({
      merchant: { name: "ファミリーマート (FamilyMart Tokyo)", address: null, taxId: null, confidence: 1 },
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("ファミリーマート");
  });

  test("B6.5 should preserve Cyrillic and Eastern European diacritics", () => {
    const r = createBoundaryReceipt({
      merchant: { name: "Kraków Restauracja & Café Łódź", address: null, taxId: null, confidence: 1 },
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("Kraków Restauracja & Café Łódź");
  });
});

describe("Tier 2: Boundary 7 — Extreme Transaction Amounts (0.01€ to 1,000,000.00€)", () => {
  test("B7.1 should handle minimal transaction: 0.01€ (1 Cent)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 0.01, confidence: 1 },
      netAmount: 0.01,
      taxBreakdown: [{ ratePercent: 0, taxAmount: 0.0, netAmount: 0.01 }],
      lineItems: [{ description: "Plastic Bag", quantity: 1, price: 0.01, taxRate: 0 }],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
    expect(val.calculatedGross).toBe(0.01);
  });

  test("B7.2 should handle large enterprise purchase: 99,999.99€", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 99999.99, confidence: 1 },
      netAmount: 84033.61,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 15966.38, netAmount: 84033.61 }],
      lineItems: [{ description: "Enterprise Server Rack", quantity: 1, price: 99999.99, taxRate: 19 }],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B7.3 should handle 1,000,000.00€ transaction", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 1000000.0, confidence: 1 },
      netAmount: 840336.13,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 159663.87, netAmount: 840336.13 }],
    });
    const val = validateReceiptMath(r);
    expect(val.isMathValid).toBe(true);
  });

  test("B7.4 Accounting CSV should format 1234567.89 as '1234567,89'", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 1234567.89, confidence: 1 },
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"1234567,89"');
  });

  test("B7.5 Excel export should write large numbers as numeric values without NaN", async () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 500000.5, confidence: 1 },
      netAmount: 420168.49,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 79832.01, netAmount: 420168.49 }],
    });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s1 = wb.getWorksheet("Belegübersicht");
    expect(s1?.getRow(2).getCell(10).value).toBe(500000.5);
  });
});

describe("Tier 2: Boundary 8 — Strict 0px Border & Zenith Silver Component Style Audits", () => {
  const componentPaths = [
    "src/components/landing/Header.tsx",
    "src/components/landing/HeroSection.tsx",
    "src/components/landing/SocialProofSection.tsx",
    "src/components/landing/FeaturesSection.tsx",
    "src/components/landing/ComparisonTable.tsx",
    "src/components/landing/FAQSection.tsx",
    "src/components/landing/Footer.tsx",
    "src/components/dashboard/Sidebar.tsx",
    "src/components/dashboard/TopNav.tsx",
    "src/components/dashboard/LiveTable.tsx",
    "src/components/dashboard/ExportBar.tsx",
    "src/app/(app)/dashboard/page.tsx",
    "src/app/(app)/dashboard/activity/page.tsx",
    "src/app/(app)/dashboard/export/page.tsx",
    "src/app/(app)/dashboard/settings/page.tsx",
  ];

  test("B8.1 verify existence of all 15 audited Zenith Silver components & routes", () => {
    componentPaths.forEach((relPath) => {
      const fullPath = path.resolve(process.cwd(), relPath);
      expect(fs.existsSync(fullPath)).toBe(true);
    });
  });

  test("B8.2 audit components for absence of soft rounded cards (rounded-2xl, rounded-3xl)", () => {
    componentPaths.forEach((relPath) => {
      const fullPath = path.resolve(process.cwd(), relPath);
      const content = fs.readFileSync(fullPath, "utf-8");
      // Check for rounded-2xl or rounded-3xl which are banned under Zenith Silver 0px design system
      expect(content).not.toMatch(/rounded-2xl/);
      expect(content).not.toMatch(/rounded-3xl/);
    });
  });

  test("B8.3 audit components for Zenith Silver border tokens (#E2E8F0)", () => {
    const sample = fs.readFileSync(path.resolve(process.cwd(), "src/components/dashboard/Sidebar.tsx"), "utf-8");
    expect(sample).toContain("#E2E8F0");
  });

  test("B8.4 audit Landing Header for sticky 0px frame structure", () => {
    const header = fs.readFileSync(path.resolve(process.cwd(), "src/components/landing/Header.tsx"), "utf-8");
    expect(header).toContain("sticky");
    expect(header).toContain("border-b");
  });

  test("B8.5 audit LiveTable for sharp 0px borders", () => {
    const liveTable = fs.readFileSync(path.resolve(process.cwd(), "src/components/dashboard/LiveTable.tsx"), "utf-8");
    expect(liveTable).toContain("border-collapse");
  });
});

describe("Tier 2: Boundary 9 — Line Item Extremes (Empty List, 100+ Items)", () => {
  test("B9.1 should handle receipt with 0 line items without crashing", () => {
    const r = createBoundaryReceipt({ lineItems: [] });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(0);
  });

  test("B9.2 should handle receipt with 100 line items", () => {
    const items = Array.from({ length: 100 }, (_, i) => ({
      description: `Wholesale Item #${i + 1}`,
      quantity: 1,
      price: 2.5,
      taxRate: 19,
    }));
    const r = createBoundaryReceipt({
      totalAmount: { value: 250.0, confidence: 1 },
      netAmount: 210.08,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 39.92, netAmount: 210.08 }],
      lineItems: items,
    });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(250.0);
    expect(val.isMathValid).toBe(true);
  });

  test("B9.3 should populate all 100 line items into Excel Sheet 2", async () => {
    const items = Array.from({ length: 100 }, (_, i) => ({
      description: `Wholesale Item #${i + 1}`,
      quantity: 1,
      price: 2.5,
      taxRate: 19,
    }));
    const r = createBoundaryReceipt({ lineItems: items });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s2 = wb.getWorksheet("Einzelpositionen Detail");
    expect(s2?.rowCount).toBe(101); // 1 header + 100 items
  });

  test("B9.4 should handle line items with large quantity (e.g. quantity 500)", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 1000.0, confidence: 1 },
      lineItems: [{ description: "Screws Bulk", quantity: 500, price: 1000.0, taxRate: 19 }],
    });
    const val = validateReceiptMath(r);
    expect(val.calculatedItemsSum).toBe(1000.0);
  });

  test("B9.5 should handle line items with emoji and special punctuation in description", async () => {
    const r = createBoundaryReceipt({
      lineItems: [
        { description: "☕ Bio Espresso & 🥐 Croissant (2x) [Special!]", quantity: 1, price: 8.5, taxRate: 19 },
      ],
    });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s2 = wb.getWorksheet("Einzelpositionen Detail");
    expect(s2?.getRow(2).getCell(4).value).toContain("Bio Espresso");
  });
});

describe("Tier 2: Boundary 10 — Date Format Variances & Leap Years", () => {
  test("B10.1 should format standard ISO date 2026-08-15 as 15.08.2026", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "2026-08-15", time: null, confidence: 1 } });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("15.08.2026");
  });

  test("B10.2 should handle leap year date 2028-02-29", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "2028-02-29", time: null, confidence: 1 } });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("29.02.2028");
  });

  test("B10.3 should handle year-end transition date 2026-12-31", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "2026-12-31", time: "23:59", confidence: 1 } });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("31.12.2026");
  });

  test("B10.4 should flag review when date confidence < 0.80", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "2026-08-15", time: null, confidence: 0.75 } });
    const val = validateReceiptMath(r);
    expect(val.needsUserReview).toBe(true);
    expect(val.reviewField).toBe("date");
  });

  test("B10.5 should not alter date format if already formatted non-ISO", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "15.08.2026", time: null, confidence: 1 } });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("15.08.2026");
  });
});

describe("Tier 2: Boundary 11 — Confidence Score Boundary Limits", () => {
  test("B11.1 Total confidence exactly 0.85 should NOT trigger review", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 50.0, confidence: 0.85 },
      netAmount: 42.02,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 7.98, netAmount: 42.02 }],
      lineItems: [{ description: "Item", quantity: 1, price: 50.0, taxRate: 19 }],
    });
    const val = validateReceiptMath(r);
    expect(val.needsUserReview).toBe(false);
  });

  test("B11.2 Total confidence 0.849 should trigger review on totalAmount", () => {
    const r = createBoundaryReceipt({
      totalAmount: { value: 50.0, confidence: 0.849 },
      netAmount: 42.02,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 7.98, netAmount: 42.02 }],
      lineItems: [{ description: "Item", quantity: 1, price: 50.0, taxRate: 19 }],
    });
    const val = validateReceiptMath(r);
    expect(val.needsUserReview).toBe(true);
    expect(val.reviewField).toBe("totalAmount");
  });

  test("B11.3 Date confidence exactly 0.80 should NOT trigger review", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "2026-08-15", time: null, confidence: 0.8 } });
    const val = validateReceiptMath(r);
    expect(val.needsUserReview).toBe(false);
  });

  test("B11.4 Date confidence 0.799 should trigger review on date", () => {
    const r = createBoundaryReceipt({ date: { isoDate: "2026-08-15", time: null, confidence: 0.799 } });
    const val = validateReceiptMath(r);
    expect(val.needsUserReview).toBe(true);
    expect(val.reviewField).toBe("date");
  });

  test("B11.5 Merchant confidence 0.749 should trigger review on merchant", () => {
    const r = createBoundaryReceipt({
      merchant: { name: "Vendor", address: null, taxId: null, confidence: 0.749 },
    });
    const val = validateReceiptMath(r);
    expect(val.needsUserReview).toBe(true);
    expect(val.reviewField).toBe("merchant");
  });
});

describe("Tier 2: Boundary 12 — Excel Formula Escaping & Malicious Payload Sanitization", () => {
  test("B12.1 should safely handle merchant names starting with formula injection characters (=, +, -, @)", async () => {
    const r = createBoundaryReceipt({
      merchant: { name: "=CMD|' /C calc'!A0", address: null, taxId: null, confidence: 1 },
    });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s1 = wb.getWorksheet("Belegübersicht");
    expect(s1?.getRow(2).getCell(3).value).toBe("=CMD|' /C calc'!A0");
  });

  test("B12.2 should handle long merchant names (300+ characters) without throwing", async () => {
    const longName = "A".repeat(300);
    const r = createBoundaryReceipt({
      merchant: { name: longName, address: null, taxId: null, confidence: 1 },
    });
    const buf = await generateDualSheetExcel([r]);
    expect(buf.length).toBeGreaterThan(1000);
  });

  test("B12.3 should preserve sheet names within 31 chars Excel limit", async () => {
    const buf = await generateDualSheetExcel([createBoundaryReceipt()]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    wb.worksheets.forEach((ws) => {
      expect(ws.name.length).toBeLessThanOrEqual(31);
    });
  });

  test("B12.4 should handle missing receiptNumber gracefully with '-' in Excel", async () => {
    const r = createBoundaryReceipt({ receiptNumber: null });
    const buf = await generateDualSheetExcel([r]);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s1 = wb.getWorksheet("Belegübersicht");
    expect(s1?.getRow(2).getCell(6).value).toBe("-");
  });

  test("B12.5 should handle batch of 50 receipts in Excel generation", async () => {
    const batch = Array.from({ length: 50 }, (_, i) =>
      createBoundaryReceipt({ id: `b-50-${i}`, totalAmount: { value: i + 1, confidence: 1 } })
    );
    const buf = await generateDualSheetExcel(batch);
    const wb = new ExcelJS.Workbook();
    await wb.xlsx.load(buf as any);
    const s1 = wb.getWorksheet("Belegübersicht");
    expect(s1?.rowCount).toBe(52); // 1 header + 50 rows + 1 summary
  });
});

describe("Tier 2: Boundary 13 — Accounting CSV Escaping & Complex Delimiters", () => {
  test("B13.1 should escape semicolons inside merchant name", () => {
    const r = createBoundaryReceipt({
      merchant: { name: "München Tankstelle; Filiale 42", address: null, taxId: null, confidence: 1 },
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"München Tankstelle; Filiale 42"');
  });

  test("B13.2 should escape nested double quotes in merchant name per RFC 4180", () => {
    const r = createBoundaryReceipt({
      merchant: { name: 'Restaurant "Zur goldenen Gans"', address: null, taxId: null, confidence: 1 },
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('""Zur goldenen Gans""');
  });

  test("B13.3 should preserve German umlauts (Ä, Ö, Ü, ß) in CSV", () => {
    const r = createBoundaryReceipt({
      merchant: { name: "Bäckerei Schönbrunn & Süßwaren", address: null, taxId: null, confidence: 1 },
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain("Bäckerei Schönbrunn & Süßwaren");
  });

  test("B13.4 should format empty receiptNumber as empty quoted string in CSV", () => {
    const r = createBoundaryReceipt({ receiptNumber: null });
    const csv = generateAccountingCsv([r]);
    const row = csv.split("\r\n")[1];
    expect(row).toContain('""');
  });

  test("B13.5 should correctly populate booking text (Buchungstext) column", () => {
    const r = createBoundaryReceipt({
      merchant: { name: "Aral", address: null, taxId: null, confidence: 1 },
      suggestedCategory: "Tanken & KFZ",
    });
    const csv = generateAccountingCsv([r]);
    expect(csv).toContain('"Aral - Tanken & KFZ"');
  });
});

describe("Tier 2: Boundary 14 — Image Preprocessing Boundaries (Tiny, Giant, Extreme Ratios)", () => {
  test("B14.1 should process minimal 1x1 image buffer cleanly", async () => {
    const png1x1 = Buffer.from(
      "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
      "base64"
    );
    const res = await processReceiptImage(png1x1, "image/png");
    expect(res.width).toBe(1);
    expect(res.height).toBe(1);
    expect(res.sha256Hash).toHaveLength(64);
  });

  test("B14.2 should generate valid base64 data URL with JPEG prefix", async () => {
    const png1x1 = Buffer.from(
      "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
      "base64"
    );
    const res = await processReceiptImage(png1x1, "image/png");
    expect(res.base64DataUrl?.startsWith("data:image/jpeg;base64,")).toBe(true);
  });

  test("B14.3 should reject uncompressed raw buffers instead of passing them through", async () => {
    // Raw-fallback removal: a buffer with no image signature must be refused.
    const raw = Buffer.alloc(500, 0xff);
    let rejected = false;
    try {
      await processReceiptImage(raw, "image/jpeg");
    } catch {
      rejected = true;
    }
    expect(rejected).toBe(true);
  });

  test("B14.4 should track original vs processed byte sizes", async () => {
    const png1x1 = Buffer.from(
      "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
      "base64"
    );
    const res = await processReceiptImage(png1x1, "image/png");
    expect(res.originalSizeBytes).toBe(png1x1.length);
    expect(res.processedSizeBytes).toBeGreaterThan(0);
  });

  test("B14.5 should compute SHA-256 hash on input before any transform", async () => {
    // Valid 1x1 PNG (real magic bytes) — the hash is taken over the raw input
    // before any sharp transform.
    const png1x1 = Buffer.from(
      "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
      "base64"
    );
    const res = await processReceiptImage(png1x1, "image/png");
    const crypto = await import("crypto");
    const expectedHash = crypto.createHash("sha256").update(png1x1).digest("hex");
    expect(res.sha256Hash).toBe(expectedHash);
  });
});

describe("Tier 2: Boundary 15 — Duplicate Detection & UUID Collision Resistance", () => {
  test("B15.1 should detect identical SHA-256 hashes for re-uploaded duplicate receipts", async () => {
    // Valid 1x1 PNG — identical bytes must produce identical hashes.
    const png1x1 = Buffer.from(
      "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
      "base64"
    );
    const resA = await processReceiptImage(png1x1, "image/png");
    const resB = await processReceiptImage(png1x1, "image/png");
    expect(resA.sha256Hash).toBe(resB.sha256Hash);
  });

  test("B15.2 should produce unique random receipt IDs across 1,000 rapid iterations", () => {
    const ids = new Set<string>();
    for (let i = 0; i < 1000; i++) {
      const id = `rcpt_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
      ids.add(id);
    }
    expect(ids.size).toBe(1000);
  });

  test("B15.3 should set isDuplicateSuspected flag in schema", () => {
    const r = createBoundaryReceipt({
      validation: {
        isMathValid: true,
        isDuplicateSuspected: true,
        needsUserReview: true,
        reviewField: "none",
        reviewReason: "Mögliches Duplikat erkannt",
      },
    });
    expect(r.validation.isDuplicateSuspected).toBe(true);
  });

  test("B15.4 should maintain ID and createdAt upon status update", () => {
    const original = createBoundaryReceipt({ id: "fix-id-1", createdAt: "2026-08-15T10:00:00.000Z" });
    const updated: ProcessedReceipt = {
      ...original,
      status: "needs_review",
      updatedAt: "2026-08-15T11:00:00.000Z",
    };
    expect(updated.id).toBe(original.id);
    expect(updated.createdAt).toBe(original.createdAt);
    expect(updated.status).toBe("needs_review");
  });

  test("B15.5 should preserve raw text field if provided by OCR model", () => {
    const r = createBoundaryReceipt({ rawText: "ARAL TANKSTELLE\nSUPER E10 50,00 EUR" });
    expect(r.rawText).toContain("ARAL TANKSTELLE");
  });
});
