/**
 * Milestone 3 (R3): Interactive Live Table & Batch Operations — Adversarial Stress Suite
 * Empirical Challenger Verification
 *
 * Stress-tests:
 * 1. Filter edge cases: special characters, regex meta-chars in search (`.*+?^${}()`), empty strings, whitespace-only, emojis
 * 2. Amount boundary testing: 0.00 €, negative amounts, high numbers (999999.99 €), German comma vs English dot decimals
 * 3. Temporal edge cases: Leap years, boundary dates (Jan 1 / Dec 31), invalid dates, malformed ISO strings
 * 4. Multi-selection boundary stress: Rapid toggle, select-all with 0 items, select-all with 1000 items, invalid range IDs
 * 5. Bulk operation stress: Bulk export with empty list, bulk export with mixed tax rates, bulk categorization on corrupted records
 * 6. Inline editing stress: Rapid successive edits, invalid date strings, NaN gross amounts, missing merchant names
 * 7. Status tier resolution stress: Null validation, missing issues, partial receipts, corrupt status enums
 */

import { describe, test, it, expect, beforeEach } from "./runner";
import { ProcessedReceipt, ReceiptCategory } from "../../src/lib/schema/receipt";
import {
  resolveReceiptStatusTier,
  getStatusTierMeta,
} from "../../src/components/dashboard/StatusBadge";
import { recalculateReceipt, confirmReceiptReviewed } from "../../src/lib/ai/recalculate";
import { generateDualSheetExcel } from "../../src/lib/export/excelGenerator";
import { generateAccountingCsv } from "../../src/lib/export/csvGenerator";

function createStressReceipt(overrides: Partial<ProcessedReceipt> = {}): ProcessedReceipt {
  return {
    id: "stress-rcpt-001",
    imageHash: "hash-stress-999",
    originalFileName: "stress_receipt.jpg",
    fileSizeBytes: 200000,
    previewUrl: "blob:http://localhost/stress.jpg",
    createdAt: "2026-08-15T12:00:00.000Z",
    updatedAt: "2026-08-15T12:00:00.000Z",
    status: "ready",
    documentType: "KASSENBON",
    receiptNumber: "STR-001",
    currency: "EUR",
    merchant: {
      name: "Standard Merchant",
      address: "Musterstr. 1, Berlin",
      taxId: "DE123456789",
      confidence: 0.95,
    },
    date: {
      isoDate: "2026-08-15",
      time: "12:00",
      confidence: 0.95,
    },
    totalAmount: {
      value: 100.0,
      confidence: 0.95,
    },
    netAmount: 84.03,
    taxBreakdown: [{ ratePercent: 19, taxAmount: 15.97, netAmount: 84.03 }],
    lineItems: [],
    suggestedCategory: "Sonstiges",
    paymentMethod: "BAR",
    validation: {
      isMathValid: true,
      isDuplicateSuspected: false,
      needsUserReview: false,
      userConfirmed: false,
      reviewField: "none",
      reviewReason: null,
      issues: [],
    },
    ...overrides,
  };
}

describe("Milestone 3 (R3) Adversarial: Search Query & Filter Robustness", () => {
  const receipts = [
    createStressReceipt({
      id: "r1",
      merchant: { name: "Bäckerei Müller (GmbH & Co. KG)", address: "Hauptstr. [42]", taxId: "DE999", confidence: 0.9 },
      receiptNumber: "INV-2026/08+01",
      date: { isoDate: "2026-08-15", time: "08:00", confidence: 0.9 },
      totalAmount: { value: 12.5, confidence: 0.9 },
      suggestedCategory: "Bewirtung",
    }),
    createStressReceipt({
      id: "r2",
      merchant: { name: "Shell Tankstelle *** Sonderaktion ***", address: "Autobahn A8", taxId: "DE888", confidence: 0.9 },
      receiptNumber: "SH-$$$-99",
      date: { isoDate: "2026-08-10", time: "14:00", confidence: 0.9 },
      totalAmount: { value: 89.9, confidence: 0.9 },
      suggestedCategory: "Tanken & KFZ",
    }),
  ];

  test("ADV-M3.1: Search query with regex special characters does not crash matcher", () => {
    const specialQueries = ["[42]", "***", "$$$", "+01", "(GmbH", ".*+?^${}()|[]\\"];
    for (const query of specialQueries) {
      const term = query.toLowerCase();
      const filtered = receipts.filter(
        (r) =>
          r.merchant?.name.toLowerCase().includes(term) ||
          r.merchant?.address?.toLowerCase().includes(term) ||
          r.receiptNumber?.toLowerCase().includes(term)
      );
      expect(Array.isArray(filtered)).toBe(true);
    }
  });

  test("ADV-M3.2: Handles German comma vs English dot decimal searches gracefully", () => {
    const queryDe = "12,50";
    const queryEn = "12.50";
    const matchAmount = (q: string) => {
      return receipts.filter((r) => {
        const gross = (r.totalAmount?.value || 0).toFixed(2);
        const grossDe = gross.replace(".", ",");
        return gross.includes(q) || grossDe.includes(q);
      });
    };

    expect(matchAmount(queryDe)).toHaveLength(1);
    expect(matchAmount(queryEn)).toHaveLength(1);
  });

  test("ADV-M3.3: Amount range boundary checks handles 0.00 €, high caps, and inverted bounds", () => {
    const filterAmount = (min: number | null, max: number | null) => {
      return receipts.filter((r) => {
        const gross = r.totalAmount?.value || 0;
        if (min !== null && gross < min) return false;
        if (max !== null && gross > max) return false;
        return true;
      });
    };

    expect(filterAmount(0, 0)).toHaveLength(0);
    expect(filterAmount(0, 1000000)).toHaveLength(2);
    expect(filterAmount(100, 50)).toHaveLength(0); // Inverted bounds returns 0 cleanly
  });
});

describe("Milestone 3 (R3) Adversarial: Selection State Integrity", () => {
  test("ADV-M3.4: Rapid toggling and duplicate selection handling maintains clean uniqueness", () => {
    let selected: string[] = [];
    const addOrToggle = (id: string) => {
      selected = selected.includes(id) ? selected.filter((x) => x !== id) : [...selected, id];
    };

    for (let i = 0; i < 100; i++) {
      addOrToggle("item-rapid");
    }
    // 100 toggles = even number of toggles -> unselected (empty)
    expect(selected).toHaveLength(0);
  });

  test("ADV-M3.5: Range selection with invalid or unlisted boundary IDs handles gracefully", () => {
    const list = ["id-1", "id-2", "id-3"];
    const selectRange = (from: string, to: string, all: string[]) => {
      const idx1 = all.indexOf(from);
      const idx2 = all.indexOf(to);
      if (idx1 === -1 || idx2 === -1) return [];
      const start = Math.min(idx1, idx2);
      const end = Math.max(idx1, idx2);
      return all.slice(start, end + 1);
    };

    expect(selectRange("non-existent-1", "id-2", list)).toEqual([]);
    expect(selectRange("id-1", "non-existent-2", list)).toEqual([]);
  });
});

describe("Milestone 3 (R3) Adversarial: Inline Recalculation & Extreme Math Values", () => {
  test("ADV-M3.6: Recalculates gross when amount is set to 0.00 € without NaN or Infinity", () => {
    const rcpt = createStressReceipt({
      totalAmount: { value: 100.0, confidence: 1.0 },
      netAmount: 84.03,
      taxBreakdown: [{ ratePercent: 19, taxAmount: 15.97, netAmount: 84.03 }],
    });

    const updated = {
      ...rcpt,
      totalAmount: { ...rcpt.totalAmount, value: 0.0 },
    };

    const recalculated = recalculateReceipt(updated, { editedField: "totalAmount" });
    expect(recalculated.totalAmount.value).toBe(0.0);
    expect(recalculated.netAmount).toBe(0.0);
    expect(recalculated.taxBreakdown[0].taxAmount).toBe(0.0);
    expect(isNaN(recalculated.netAmount ?? 0)).toBe(false);
  });

  test("ADV-M3.7: Recalculates gross with mixed 7% and 19% VAT rates", () => {
    const rcpt = createStressReceipt({
      totalAmount: { value: 100.0, confidence: 1.0 },
      netAmount: 88.0,
      taxBreakdown: [
        { ratePercent: 7, taxAmount: 3.5, netAmount: 50.0 },
        { ratePercent: 19, taxAmount: 8.5, netAmount: 38.0 },
      ],
    });

    const updated = {
      ...rcpt,
      totalAmount: { ...rcpt.totalAmount, value: 200.0 },
    };

    const recalculated = recalculateReceipt(updated, { editedField: "totalAmount" });
    expect(recalculated.totalAmount.value).toBe(200.0);
    expect(recalculated.validation.isMathValid).toBe(true);
  });
});

describe("Milestone 3 (R3) Adversarial: Bulk Export Formats & CSV Encoding", () => {
  test("ADV-M3.8: Dual-sheet Excel export generates Sheet 1 and Sheet 2 correctly", async () => {
    const largeBatch = Array.from({ length: 25 }, (_, i) =>
      createStressReceipt({
        id: `batch-stress-${i}`,
        merchant: { name: `Händler Nr. ${i}`, address: "Berlin", taxId: "DE123", confidence: 1.0 },
        totalAmount: { value: 10.0 * (i + 1), confidence: 1.0 },
      })
    );

    const buffer = await generateDualSheetExcel(largeBatch);
    expect(buffer).toBeDefined();
    expect(buffer.length).toBeGreaterThan(5000);
  });

  test("ADV-M3.9: Accounting CSV export handles receipts with quotes, line breaks, and umlauts in merchant name", () => {
    const specialReceipt = createStressReceipt({
      merchant: { name: 'Möbel "Schön & Weiß" GmbH\nFiliale Süd', address: "München", taxId: "DE1", confidence: 1.0 },
      totalAmount: { value: 199.99, confidence: 1.0 },
    });

    const csv = generateAccountingCsv([specialReceipt]);
    expect(csv).toBeDefined();
    expect(csv.charCodeAt(0)).toBe(0xfeff); // UTF-8 BOM
    expect(csv).toContain("Möbel");
  });
});
