"use client";

import React, { useCallback, useMemo, useRef, useState } from "react";
import { useI18n } from "@/lib/i18n/context";
import {
  ProcessedReceipt,
  ReceiptCategory,
  DocumentType,
  PaymentMethod,
  TaxBreakdownItem,
} from "@/lib/schema/receipt";
import {
  recalculateReceipt,
  confirmReceiptReviewed,
  receiptNeedsAttention,
  EditedReceiptField,
} from "@/lib/ai/recalculate";
import { CONFIDENCE_THRESHOLDS } from "@/lib/ai/mathValidator";
import {
  collectTaxRates,
  formatAmountInput,
  formatMoney,
  grossOf,
  netOf,
  parseAmountInput,
  receiptCurrency,
  taxAmountForRate,
  taxRateLabel,
} from "./receiptFormat";
import { StatusBadge, ReceiptStatusTier, resolveReceiptStatusTier } from "./StatusBadge";
import { BatchActionBar, BatchActionBarProject } from "./BatchActionBar";
import {
  FileSpreadsheet,
  AlertTriangle,
  CheckCircle2,
  Trash2,
  Eye,
  Image as ImageIcon,
  ArrowUp,
  ArrowDown,
  Filter,
  UserCheck,
  X,
  Pencil,
  Sparkles,
  CreditCard,
  Download,
} from "lucide-react";
import { downloadReceiptImage } from "@/lib/utils/imageDownload";

export interface LiveTableProps {
  receipts: ProcessedReceipt[];
  onUpdateReceipt: (updated: ProcessedReceipt) => void;
  onDeleteReceipt: (id: string) => void;
  onViewDetails: (receipt: ProcessedReceipt) => void;
  /** Optional focus receipt ID */
  focusReceiptId?: string | null;
  /** Whether to show top summary / filter toolbar */
  showToolbar?: boolean;
  /** View-only mode: hides add/edit/delete/selection affordances, leaves inspection (image, details) intact */
  readOnly?: boolean;
  /** Optional externally controlled selection state */
  selectedIds?: string[];
  onToggleSelect?: (id: string) => void;
  onToggleSelectAll?: () => void;
  onClearSelection?: () => void;
  onBulkDelete?: (ids: string[]) => void | Promise<void>;
  onBulkCategorize?: (ids: string[], category: ReceiptCategory) => void | Promise<void>;
  onBulkStatusUpdate?: (ids: string[], status: ReceiptStatusTier) => void | Promise<void>;
  onBulkExport?: (ids: string[], format: "xlsx" | "csv" | "pdf" | "json") => void | Promise<void>;
  /** Pro-only "move selection to project" — omitted/empty hides the control (see BatchActionBar). */
  projects?: BatchActionBarProject[];
  onBulkMoveToProject?: (ids: string[], projectId: string | null) => void | Promise<void>;
}

const CATEGORIES: ReceiptCategory[] = [
  "Bewirtung",
  "Reisekosten & Hotel",
  "Tanken & KFZ",
  "Bürobedarf & IT",
  "Verpflegungsmehraufwand",
  "Material & Einkauf",
  "Sonstiges",
];

export const CATEGORY_LABELS: Record<ReceiptCategory, { de: string; en: string }> = {
  "Bewirtung": { de: "Bewirtung", en: "Meals & Entertainment" },
  "Reisekosten & Hotel": { de: "Reisekosten & Hotel", en: "Travel & Lodging" },
  "Tanken & KFZ": { de: "Tanken & KFZ", en: "Fuel & Vehicle" },
  "Bürobedarf & IT": { de: "Bürobedarf & IT", en: "Office Supplies & IT" },
  "Verpflegungsmehraufwand": { de: "Verpflegungsmehraufwand", en: "Per Diem / Subsistence" },
  "Material & Einkauf": { de: "Material & Einkauf", en: "Supplies & Inventory" },
  "Sonstiges": { de: "Sonstiges", en: "Other / Misc" },
};

const DOC_TYPES: DocumentType[] = [
  "KASSENBON",
  "RECHNUNG",
  "TANKBELEG",
  "BEWIRTUNGSBELEG",
  "PARKTICKET",
  "SONSTIGES",
];

export const DOC_TYPE_LABELS: Record<DocumentType, { de: string; en: string }> = {
  "KASSENBON": { de: "KASSENBON", en: "RECEIPT" },
  "RECHNUNG": { de: "RECHNUNG", en: "INVOICE" },
  "TANKBELEG": { de: "TANKBELEG", en: "FUEL TICKET" },
  "BEWIRTUNGSBELEG": { de: "BEWIRTUNGSBELEG", en: "RESTAURANT RECEIPT" },
  "PARKTICKET": { de: "PARKTICKET", en: "PARKING TICKET" },
  "SONSTIGES": { de: "SONSTIGES", en: "OTHER" },
};

const PAYMENT_METHODS: Array<{ value: PaymentMethod; labelDe: string; labelEn: string }> = [
  { value: "BAR", labelDe: "Bar", labelEn: "Cash" },
  { value: "EC_KARTE", labelDe: "EC-Karte / Girocard", labelEn: "Debit Card / Girocard" },
  { value: "KREDITKARTE", labelDe: "Kreditkarte", labelEn: "Credit Card" },
  { value: "UEBERWEISUNG", labelDe: "Überweisung", labelEn: "Bank Transfer" },
  { value: "PAYPAL", labelDe: "PayPal", labelEn: "PayPal" },
  { value: "APPLE_PAY", labelDe: "Apple Pay", labelEn: "Apple Pay" },
  { value: "GOOGLE_PAY", labelDe: "Google Pay", labelEn: "Google Pay" },
  { value: "SONSTIGE", labelDe: "Sonstige", labelEn: "Other" },
];

type SortKey = "date" | "merchant" | "category" | "gross" | "status";
type SortDirection = "asc" | "desc";

const TAX_FIELD_PREFIX = "tax:";

/** Steuersatz aus einer Feldkennung wie `tax:19` lesen. */
function rateFromField(field: string): number | null {
  if (!field.startsWith(TAX_FIELD_PREFIX)) return null;
  const rate = Number(field.slice(TAX_FIELD_PREFIX.length));
  return Number.isFinite(rate) ? rate : null;
}

export function LiveTable({
  receipts,
  onUpdateReceipt,
  onDeleteReceipt,
  onViewDetails,
  focusReceiptId = null,
  showToolbar = true,
  readOnly = false,
  selectedIds: externalSelectedIds,
  onToggleSelect: externalToggleSelect,
  onToggleSelectAll: externalToggleSelectAll,
  onClearSelection: externalClearSelection,
  onBulkDelete: externalBulkDelete,
  onBulkCategorize: externalBulkCategorize,
  onBulkStatusUpdate: externalBulkStatusUpdate,
  onBulkExport: externalBulkExport,
  projects,
  onBulkMoveToProject,
}: LiveTableProps) {
  const { language } = useI18n();
  const isDe = language === "de";

  const [editing, setEditing] = useState<{ id: string; field: string } | null>(null);
  const [draft, setDraft] = useState<string>("");
  const [reviewOnly, setReviewOnly] = useState(false);
  const [sortKey, setSortKey] = useState<SortKey | null>(null);
  const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
  const [internalSelectedIds, setInternalSelectedIds] = useState<string[]>([]);
  const [openPanelId, setOpenPanelId] = useState<string | null>(focusReceiptId);
  const [lastFocusRequest, setLastFocusRequest] = useState<string | null>(focusReceiptId);
  const [lastSelectedId, setLastSelectedId] = useState<string | null>(null);

  // Active selection list (external or internal fallback)
  const selectedIds = externalSelectedIds ?? internalSelectedIds;

  const skipBlurRef = useRef(false);
  const cellRefs = useRef(new Map<string, HTMLTableCellElement>());
  const headerCheckboxRef = useRef<HTMLInputElement>(null);

  // Focus request handling
  if (focusReceiptId && focusReceiptId !== lastFocusRequest) {
    setLastFocusRequest(focusReceiptId);
    setOpenPanelId(focusReceiptId);
  }

  const taxRates = useMemo(() => collectTaxRates(receipts), [receipts]);

  /** Navigable fields for spreadsheet keyboard arrow navigation */
  const navFields = useMemo(
    () => [
      "date",
      "merchant",
      "category",
      "paymentMethod",
      "receiptNumber",
      "net",
      ...taxRates.map((rate) => `${TAX_FIELD_PREFIX}${rate}`),
      "gross",
    ],
    [taxRates]
  );

  const reviewCount = useMemo(
    () => receipts.filter((r) => receiptNeedsAttention(r)).length,
    [receipts]
  );

  const visibleReceipts = useMemo(() => {
    const filtered = reviewOnly
      ? receipts.filter((r) => receiptNeedsAttention(r))
      : receipts;
    if (!sortKey) return filtered;
    const factor = sortDirection === "asc" ? 1 : -1;
    return [...filtered].sort((a, b) => {
      switch (sortKey) {
        case "date":
          return factor * (a.date?.isoDate ?? "").localeCompare(b.date?.isoDate ?? "");
        case "merchant":
          return factor * (a.merchant?.name ?? "").localeCompare(b.merchant?.name ?? "", "de");
        case "category":
          return factor * (a.suggestedCategory ?? "").localeCompare(b.suggestedCategory ?? "", "de");
        case "gross":
          return factor * (grossOf(a) - grossOf(b));
        case "status": {
          const tierA = resolveReceiptStatusTier(a);
          const tierB = resolveReceiptStatusTier(b);
          return factor * tierA.localeCompare(tierB);
        }
        default:
          return 0;
      }
    });
  }, [receipts, reviewOnly, sortKey, sortDirection]);

  // Update header checkbox indeterminate state
  const allVisibleSelected =
    visibleReceipts.length > 0 &&
    visibleReceipts.every((r) => selectedIds.includes(r.id));
  const someVisibleSelected =
    visibleReceipts.some((r) => selectedIds.includes(r.id)) && !allVisibleSelected;

  React.useEffect(() => {
    if (headerCheckboxRef.current) {
      headerCheckboxRef.current.indeterminate = someVisibleSelected;
    }
  }, [someVisibleSelected]);

  /* -------------------------------------------------------------- */
  /* Selection Handlers                                             */
  /* -------------------------------------------------------------- */

  const toggleSelection = (id: string, shiftKey: boolean = false) => {
    if (externalToggleSelect) {
      externalToggleSelect(id);
      return;
    }

    if (shiftKey && lastSelectedId) {
      const orderedIds = visibleReceipts.map((r) => r.id);
      const start = orderedIds.indexOf(lastSelectedId);
      const end = orderedIds.indexOf(id);
      if (start !== -1 && end !== -1) {
        const range = orderedIds.slice(Math.min(start, end), Math.max(start, end) + 1);
        setInternalSelectedIds((prev) => Array.from(new Set([...prev, ...range])));
        setLastSelectedId(id);
        return;
      }
    }

    setLastSelectedId(id);
    setInternalSelectedIds((prev) =>
      prev.includes(id) ? prev.filter((entry) => entry !== id) : [...prev, id]
    );
  };

  const toggleSelectAll = () => {
    if (externalToggleSelectAll) {
      externalToggleSelectAll();
      return;
    }
    setInternalSelectedIds(allVisibleSelected ? [] : visibleReceipts.map((r) => r.id));
  };

  const clearSelection = () => {
    if (externalClearSelection) {
      externalClearSelection();
    } else {
      setInternalSelectedIds([]);
    }
  };

  /* -------------------------------------------------------------- */
  /* Bulk Operations                                                */
  /* -------------------------------------------------------------- */

  const handleBulkDelete = async (ids: string[]) => {
    if (externalBulkDelete) {
      await externalBulkDelete(ids);
    } else {
      for (const id of ids) {
        onDeleteReceipt(id);
      }
      clearSelection();
    }
  };

  const handleBulkCategorize = async (ids: string[], category: ReceiptCategory) => {
    if (externalBulkCategorize) {
      await externalBulkCategorize(ids, category);
    } else {
      for (const id of ids) {
        const rcpt = receipts.find((r) => r.id === id);
        if (rcpt) {
          const updated: ProcessedReceipt = {
            ...rcpt,
            suggestedCategory: category,
            editedFields: { ...rcpt.editedFields, category: true },
            updatedAt: new Date().toISOString(),
          };
          onUpdateReceipt(recalculateReceipt(updated, { editedField: "category" }));
        }
      }
      clearSelection();
    }
  };

  const handleBulkStatusUpdate = async (ids: string[], status: ReceiptStatusTier) => {
    if (externalBulkStatusUpdate) {
      await externalBulkStatusUpdate(ids, status);
    } else {
      for (const id of ids) {
        const rcpt = receipts.find((r) => r.id === id);
        if (rcpt) {
          let updated: ProcessedReceipt;
          if (status === "confirmed") {
            updated = confirmReceiptReviewed(rcpt);
          } else if (status === "pending_review") {
            updated = {
              ...rcpt,
              status: "needs_review",
              validation: {
                ...rcpt.validation,
                needsUserReview: true,
                userConfirmed: false,
                reviewReason: isDe ? "Manuell zur Prüfung markiert" : "Manually marked for review",
              },
            };
          } else {
            updated = {
              ...rcpt,
              status: "ready",
              validation: {
                ...rcpt.validation,
                needsUserReview: false,
                userConfirmed: true,
                reviewReason: null,
              },
            };
          }
          onUpdateReceipt({ ...updated, updatedAt: new Date().toISOString() });
        }
      }
      clearSelection();
    }
  };

  /* -------------------------------------------------------------- */
  /* Editing & Calculation                                          */
  /* -------------------------------------------------------------- */

  const commitValue = useCallback(
    (receipt: ProcessedReceipt, field: string, rawValue: string) => {
      let updated: ProcessedReceipt = {
        ...receipt,
        editedFields: { ...(receipt.editedFields || {}) },
        originalExtraction: receipt.originalExtraction || { ...receipt },
      };
      let editedField: EditedReceiptField = "none";

      const rate = rateFromField(field);

      if (field === "date") {
        if (!rawValue) return;
        if (rawValue === receipt.date?.isoDate) return;
        updated = {
          ...updated,
          date: { ...receipt.date, isoDate: rawValue, confidence: 1.0 },
          editedFields: { ...updated.editedFields, date: true },
        };
        editedField = "date";
      } else if (field === "merchant") {
        const name = rawValue.trim();
        if (!name || name === receipt.merchant?.name) return;
        updated = {
          ...updated,
          merchant: { ...receipt.merchant, name, confidence: 1.0 },
          editedFields: { ...updated.editedFields, merchant: true },
        };
        editedField = "merchant";
      } else if (field === "receiptNumber") {
        const value = rawValue.trim() || null;
        if (value === (receipt.receiptNumber ?? null)) return;
        updated = {
          ...updated,
          receiptNumber: value,
          editedFields: { ...updated.editedFields, receiptNumber: true },
        };
        editedField = "none";
      } else if (field === "category") {
        if (rawValue === receipt.suggestedCategory) return;
        updated = {
          ...updated,
          suggestedCategory: rawValue as ReceiptCategory,
          editedFields: { ...updated.editedFields, category: true },
        };
        editedField = "category";
      } else if (field === "paymentMethod") {
        if (rawValue === receipt.paymentMethod) return;
        updated = {
          ...updated,
          paymentMethod: rawValue as PaymentMethod,
          editedFields: { ...updated.editedFields, paymentMethod: true },
        };
        editedField = "none";
      } else if (field === "docType") {
        if (rawValue === receipt.documentType) return;
        updated = {
          ...updated,
          documentType: rawValue as DocumentType,
          editedFields: { ...updated.editedFields, docType: true },
        };
        editedField = "none";
      } else if (field === "gross") {
        const parsed = parseAmountInput(rawValue);
        if (parsed === null || parsed === grossOf(receipt)) return;
        updated = {
          ...updated,
          totalAmount: { ...receipt.totalAmount, value: parsed, confidence: 1.0 },
          editedFields: { ...updated.editedFields, totalAmount: true },
        };
        editedField = "totalAmount";
      } else if (field === "net") {
        const parsed = parseAmountInput(rawValue);
        if (parsed === null && receipt.netAmount === null) return;
        if (parsed !== null && parsed === receipt.netAmount) return;
        updated = {
          ...updated,
          netAmount: parsed,
          editedFields: { ...updated.editedFields, netAmount: true },
        };
        editedField = "netAmount";
      } else if (rate !== null) {
        const parsed = parseAmountInput(rawValue);
        const existing = receipt.taxBreakdown ?? [];
        const current = taxAmountForRate(receipt, rate);
        if (parsed === null && current === null) return;
        if (parsed !== null && current !== null && parsed === current) return;

        let nextBreakdown: TaxBreakdownItem[];
        if (parsed === null) {
          nextBreakdown = existing.filter((item) => item?.ratePercent !== rate);
        } else if (existing.some((item) => item?.ratePercent === rate)) {
          nextBreakdown = existing.map((item) =>
            item?.ratePercent === rate ? { ...item, taxAmount: parsed } : item
          );
        } else {
          nextBreakdown = [
            ...existing,
            { ratePercent: rate, taxAmount: parsed, netAmount: null },
          ].sort((a, b) => (a.ratePercent ?? 0) - (b.ratePercent ?? 0));
        }
        updated = {
          ...updated,
          taxBreakdown: nextBreakdown,
          editedFields: { ...updated.editedFields, taxBreakdown: true },
        };
        editedField = "taxBreakdown";
      } else {
        return;
      }

      const recalculated = recalculateReceipt(updated, { editedField });
      onUpdateReceipt({ ...recalculated, updatedAt: new Date().toISOString() });
    },
    [onUpdateReceipt]
  );

  const valueForField = useCallback(
    (receipt: ProcessedReceipt, field: string): string => {
      const rate = rateFromField(field);
      if (field === "date") return receipt.date?.isoDate ?? "";
      if (field === "merchant") return receipt.merchant?.name ?? "";
      if (field === "receiptNumber") return receipt.receiptNumber ?? "";
      if (field === "category") return receipt.suggestedCategory ?? "";
      if (field === "paymentMethod") return receipt.paymentMethod ?? "";
      if (field === "gross") return formatAmountInput(grossOf(receipt));
      if (field === "net") return formatAmountInput(netOf(receipt));
      if (rate !== null) return formatAmountInput(taxAmountForRate(receipt, rate));
      return "";
    },
    []
  );

  const cellKey = (id: string, field: string) => `${id}::${field}`;

  const focusCell = useCallback((id: string, field: string) => {
    const node = cellRefs.current.get(cellKey(id, field));
    node?.focus();
  }, []);

  const beginEdit = useCallback(
    (receipt: ProcessedReceipt, field: string, initial?: string) => {
      setEditing({ id: receipt.id, field });
      setDraft(initial ?? valueForField(receipt, field));
    },
    [valueForField]
  );

  const neighbor = useCallback(
    (
      id: string,
      field: string,
      rowDelta: number,
      colDelta: number
    ): { receipt: ProcessedReceipt; field: string } | null => {
      const rowIndex = visibleReceipts.findIndex((r) => r.id === id);
      const colIndex = navFields.indexOf(field);
      if (rowIndex < 0 || colIndex < 0) return null;

      let nextRow = rowIndex + rowDelta;
      let nextCol = colIndex + colDelta;

      if (nextCol >= navFields.length) {
        nextCol = 0;
        nextRow += 1;
      } else if (nextCol < 0) {
        nextCol = navFields.length - 1;
        nextRow -= 1;
      }
      if (nextRow < 0 || nextRow >= visibleReceipts.length) return null;
      return { receipt: visibleReceipts[nextRow], field: navFields[nextCol] };
    },
    [navFields, visibleReceipts]
  );

  const handleEditorKeyDown = (
    event: React.KeyboardEvent<HTMLInputElement | HTMLSelectElement>,
    receipt: ProcessedReceipt,
    field: string
  ) => {
    if (event.key === "Escape") {
      event.preventDefault();
      event.stopPropagation();
      skipBlurRef.current = true;
      setEditing(null);
      requestAnimationFrame(() => focusCell(receipt.id, field));
      return;
    }

    if (event.key === "Enter" || event.key === "Tab") {
      event.preventDefault();
      const rowDelta = event.key === "Enter" ? 1 : 0;
      const colDelta = event.key === "Tab" ? (event.shiftKey ? -1 : 1) : 0;
      const target = neighbor(receipt.id, field, rowDelta, colDelta);

      skipBlurRef.current = true;
      commitValue(receipt, field, draft);

      if (target) {
        beginEdit(target.receipt, target.field);
      } else {
        setEditing(null);
        requestAnimationFrame(() => focusCell(receipt.id, field));
      }
    }
  };

  const handleEditorBlur = (receipt: ProcessedReceipt, field: string) => {
    if (skipBlurRef.current) {
      skipBlurRef.current = false;
      return;
    }
    commitValue(receipt, field, draft);
    setEditing(null);
  };

  const handleCellKeyDown = (
    event: React.KeyboardEvent<HTMLTableCellElement>,
    receipt: ProcessedReceipt,
    field: string
  ) => {
    if (editing) return;

    const move = (rowDelta: number, colDelta: number) => {
      const target = neighbor(receipt.id, field, rowDelta, colDelta);
      if (target) focusCell(target.receipt.id, target.field);
    };

    switch (event.key) {
      case "ArrowDown":
        event.preventDefault();
        move(1, 0);
        return;
      case "ArrowUp":
        event.preventDefault();
        move(-1, 0);
        return;
      case "ArrowRight":
        event.preventDefault();
        move(0, 1);
        return;
      case "ArrowLeft":
        event.preventDefault();
        move(0, -1);
        return;
      case "Tab":
        event.preventDefault();
        move(0, event.shiftKey ? -1 : 1);
        return;
      case "Enter":
      case "F2":
        event.preventDefault();
        beginEdit(receipt, field);
        return;
      default:
        break;
    }

    if (
      event.key.length === 1 &&
      !event.ctrlKey &&
      !event.metaKey &&
      !event.altKey &&
      field !== "date" &&
      field !== "category" &&
      field !== "paymentMethod"
    ) {
      event.preventDefault();
      beginEdit(receipt, field, event.key);
    }
  };

  const toggleSort = (key: SortKey) => {
    if (sortKey === key) {
      setSortDirection((prev) => (prev === "asc" ? "desc" : "asc"));
    } else {
      setSortKey(key);
      setSortDirection(key === "date" ? "desc" : "asc");
    }
  };

  const sortIndicator = (key: SortKey) =>
    sortKey === key ? (
      sortDirection === "asc" ? (
        <ArrowUp className="w-3 h-3 inline-block ml-1" />
      ) : (
        <ArrowDown className="w-3 h-3 inline-block ml-1" />
      )
    ) : null;

  /* -------------------------------------------------------------- */
  /* Render Empty State                                             */
  /* -------------------------------------------------------------- */

  if (receipts.length === 0) {
    return (
      <div
        data-testid="live-table-empty-state"
        className="border border-[#E2E8F0] bg-white p-12 text-center font-sans"
      >
        <div className="w-12 h-12 bg-[#F8FAFC] border border-[#E2E8F0] text-black flex items-center justify-center mx-auto mb-4">
          <FileSpreadsheet className="w-6 h-6" />
        </div>
        <h3 className="font-display text-lg font-bold text-black mb-1">
          {isDe ? "Noch keine Belege erfasst" : "No receipts scanned yet"}
        </h3>
        <p className="text-xs text-[#64748B] max-w-sm mx-auto">
          {isDe
            ? "Lade Belege per Drag & Drop oben hoch oder klicke auf „+ Beleg hochladen“, um deine Belege zu erfassen."
            : "Upload receipts via drag & drop above or click \"+ Upload Receipt\" to start scanning."}
        </p>
      </div>
    );
  }

  const columnCount = 13 + taxRates.length;

  return (
    <div data-testid="live-table-container" className="border border-[#E2E8F0] bg-white font-sans">
      {/* Top Toolbar */}
      {showToolbar && (
        <div className="flex flex-wrap items-center justify-between gap-3 border-b border-[#E2E8F0] bg-[#F8FAFC] px-3 py-2 font-mono text-[11px] uppercase tracking-caps">
          <div className="flex flex-wrap items-center gap-2">
            <button
              type="button"
              data-testid="review-filter-toggle"
              aria-pressed={reviewOnly}
              onClick={() => setReviewOnly((prev) => !prev)}
              className={`flex items-center gap-1.5 border px-3 py-1.5 transition-colors ${
                reviewOnly
                  ? "border-black bg-black text-white"
                  : "border-[#E2E8F0] bg-white text-[#475569] hover:border-black hover:text-black"
              }`}
            >
              <Filter className="h-3 w-3" />
              <span>{isDe ? "Nur Prüfen anzeigen" : "Show Review Only"}</span>
              <span
                className={`px-1.5 ${
                  reviewOnly ? "bg-white text-black" : "bg-amber-100 text-amber-900"
                }`}
              >
                {reviewCount}
              </span>
            </button>
            <span className="text-[#64748B] normal-case tracking-normal">
              {isDe
                ? `${visibleReceipts.length} von ${receipts.length} Belegen sichtbar`
                : `${visibleReceipts.length} of ${receipts.length} receipts visible`}
            </span>
          </div>

          <div className="flex items-center gap-3 text-[#94A3B8] normal-case tracking-normal text-[11px]">
            <span className="flex items-center gap-1">
              <Pencil className="w-3 h-3 text-[#64748B]" />
              <span>{isDe ? "Klick zum Bearbeiten" : "Click to edit"}</span>
            </span>
            <span>·</span>
            <span>{isDe ? "Tab/Enter wechselt" : "Tab/Enter moves"}</span>
            <span>·</span>
            <span>{isDe ? "Esc bricht ab" : "Esc cancels"}</span>
          </div>
        </div>
      )}

      {/* Table Scroller */}
      <div className="overflow-x-auto">
        <table data-testid="live-table" className="w-full text-left text-xs border-collapse">
          <thead className="bg-[#161C22] text-white font-mono text-[10px] uppercase tracking-caps select-none">
            <tr>
              {!readOnly && (
                <th className="py-3.5 px-2 w-8 text-center border-r border-slate-800">
                  <input
                    ref={headerCheckboxRef}
                    type="checkbox"
                    data-testid="select-all-checkbox"
                    aria-label={isDe ? "Alle sichtbaren Belege auswählen" : "Select all visible receipts"}
                    checked={allVisibleSelected}
                    onChange={toggleSelectAll}
                    className="h-3.5 w-3.5 accent-white rounded-none align-middle cursor-pointer"
                  />
                </th>
              )}
              <th className="py-3.5 px-2.5 w-10 text-center border-r border-slate-800">#</th>
              <th
                onClick={() => toggleSort("date")}
                className="py-3.5 px-3 w-28 border-r border-slate-800 cursor-pointer hover:bg-slate-800"
              >
                {isDe ? "DATUM" : "DATE"} {sortIndicator("date")}
              </th>
              <th
                onClick={() => toggleSort("merchant")}
                className="py-3.5 px-3 w-48 border-r border-slate-800 cursor-pointer hover:bg-slate-800"
              >
                {isDe ? "HÄNDLER / AUSSTELLER" : "MERCHANT / ISSUER"} {sortIndicator("merchant")}
              </th>
              <th
                onClick={() => toggleSort("category")}
                className="py-3.5 px-3 w-36 border-r border-slate-800 cursor-pointer hover:bg-slate-800"
              >
                {isDe ? "KATEGORIE" : "CATEGORY"} {sortIndicator("category")}
              </th>
              <th className="py-3.5 px-3 w-32 border-r border-slate-800">{isDe ? "ZAHLART" : "PAYMENT"}</th>
              <th className="py-3.5 px-3 w-28 border-r border-slate-800">{isDe ? "TYP" : "DOC TYPE"}</th>
              <th className="py-3.5 px-3 w-28 border-r border-slate-800">{isDe ? "BELEG-NR." : "RECEIPT NO."}</th>
              <th className="py-3.5 px-3 w-24 text-right border-r border-slate-800">{isDe ? "NETTO" : "NET"}</th>
              {taxRates.map((rate) => (
                <th
                  key={rate}
                  className="py-3.5 px-3 w-20 text-right border-r border-slate-800"
                >
                  {taxRateLabel(rate, isDe)}
                </th>
              ))}
              <th
                onClick={() => toggleSort("gross")}
                className="py-3.5 px-3 w-28 text-right border-r border-slate-800 font-bold cursor-pointer hover:bg-slate-800"
              >
                {isDe ? "BRUTTO" : "GROSS"} {sortIndicator("gross")}
              </th>
              <th
                onClick={() => toggleSort("status")}
                className="py-3.5 px-3 w-36 text-center border-r border-slate-800 cursor-pointer hover:bg-slate-800"
              >
                {isDe ? "STATUS" : "STATUS"} {sortIndicator("status")}
              </th>
              <th className="py-3.5 px-3 w-28 text-center">{isDe ? "AKTIONEN" : "ACTIONS"}</th>
            </tr>
          </thead>

          <tbody className="divide-y divide-[#E2E8F0] font-sans text-xs text-black">
            {visibleReceipts.length === 0 && (
              <tr>
                <td colSpan={columnCount} className="p-10 text-center">
                  <CheckCircle2 className="mx-auto mb-2 h-6 w-6 text-emerald-600" />
                  <p className="font-display text-sm font-bold text-black">
                    {isDe ? "Keine Belege entsprechen den aktuellen Filtern" : "No receipts match the current filters"}
                  </p>
                  <p className="mt-1 font-mono text-[11px] text-[#64748B]">
                    {isDe ? "Versuche die Filter zurückzusetzen." : "Try resetting the filters."}
                  </p>
                </td>
              </tr>
            )}

            {visibleReceipts.map((r, idx) => {
              const currency = receiptCurrency(r);
              const net = netOf(r);
              const gross = grossOf(r);
              const needsAttention = receiptNeedsAttention(r);
              const isPanelOpen = openPanelId === r.id;
              const isSelected = selectedIds.includes(r.id);
              const editedFields = r.editedFields || {};
              const isDemoReceipt = Boolean(r.isDemo) || r.id.startsWith("demo-");

              const renderEditableCell = (
                field: string,
                display: React.ReactNode,
                options: {
                  className?: string;
                  inputType?: string;
                  align?: "left" | "right";
                } = {}
              ) => {
                const isEditing = !readOnly && editing?.id === r.id && editing?.field === field;
                const isEdited = Array.isArray(editedFields)
                  ? editedFields.includes(field)
                  : Boolean((editedFields as Record<string, boolean>)?.[field]);

                if (readOnly) {
                  return (
                    <td
                      data-cell={`${r.id}:${field}`}
                      className={`py-2 px-2.5 border-r border-[#E2E8F0] ${
                        options.align === "right" ? "text-right" : ""
                      } ${options.className ?? ""}`}
                    >
                      <div className="truncate">{display}</div>
                    </td>
                  );
                }

                return (
                  <td
                    ref={(node) => {
                      if (node) cellRefs.current.set(cellKey(r.id, field), node);
                      else cellRefs.current.delete(cellKey(r.id, field));
                    }}
                    tabIndex={0}
                    data-cell={`${r.id}:${field}`}
                    data-edited={isEdited}
                    onClick={(e) => {
                      e.stopPropagation();
                      if (!isEditing) beginEdit(r, field);
                    }}
                    onKeyDown={(event) => handleCellKeyDown(event, r, field)}
                    className={`py-2 px-2.5 cursor-pointer border-r border-[#E2E8F0] group transition-colors relative hover:bg-[#EEF4FC] focus:outline-none focus:ring-2 focus:ring-inset focus:ring-black ${
                      options.align === "right" ? "text-right" : ""
                    } ${options.className ?? ""}`}
                  >
                    {isEditing ? (
                      <input
                        type={options.inputType ?? "text"}
                        value={draft}
                        autoFocus
                        data-testid={`editor-${field}`}
                        onChange={(event) => setDraft(event.target.value)}
                        onKeyDown={(event) => handleEditorKeyDown(event, r, field)}
                        onBlur={() => handleEditorBlur(r, field)}
                        className={`w-full text-xs border border-black bg-white p-1 focus:outline-none font-mono ${
                          options.align === "right" ? "text-right" : ""
                        }`}
                      />
                    ) : (
                      <div
                        className={`flex items-center justify-between gap-1 w-full border-b border-dotted ${
                          isEdited ? "border-blue-400" : "border-transparent group-hover:border-slate-400"
                        }`}
                      >
                        <div className="truncate flex-1">{display}</div>
                        {isEdited && (
                          <span
                            data-testid={`audit-badge-${field}-${r.id}`}
                            title={isDe ? "Manuell bearbeitet" : "Manually edited"}
                            className="w-1.5 h-1.5 rounded-full bg-blue-600 shrink-0 ml-1"
                          />
                        )}
                        <Pencil className="w-2.5 h-2.5 text-[#94A3B8] opacity-0 group-hover:opacity-100 transition-opacity shrink-0 ml-1" />
                      </div>
                    )}
                  </td>
                );
              };

              return (
                <React.Fragment key={r.id}>
                  <tr
                    data-testid={`receipt-row-${r.id}`}
                    onDoubleClick={() => onViewDetails(r)}
                    className={`transition-colors cursor-default select-none ${
                      isSelected
                        ? "bg-blue-50/70"
                        : needsAttention
                        ? "bg-amber-50/50 hover:bg-amber-100/40"
                        : idx % 2 === 1
                        ? "bg-[#F8FAFC]/40 hover:bg-[#EEF4FC]/40"
                        : "bg-white hover:bg-[#EEF4FC]/30"
                    }`}
                  >
                    {/* Row Checkbox */}
                    {!readOnly && (
                      <td
                        onClick={(e) => e.stopPropagation()}
                        className="py-2.5 px-2 text-center border-r border-[#E2E8F0]"
                      >
                        <input
                          type="checkbox"
                          data-testid={`receipt-checkbox-${r.id}`}
                          aria-label={isDe ? `Beleg ${r.merchant?.name ?? ""} auswählen` : `Select receipt ${r.merchant?.name ?? ""}`}
                          checked={isSelected}
                          onChange={(e) => toggleSelection(r.id, (e.nativeEvent as MouseEvent).shiftKey)}
                          className="h-3.5 w-3.5 accent-black rounded-none align-middle cursor-pointer"
                        />
                      </td>
                    )}

                    {/* Row Index */}
                    <td className="py-2.5 px-2.5 text-center text-[#64748B] font-mono border-r border-[#E2E8F0]">
                      {idx + 1}
                    </td>

                    {/* Date */}
                    {renderEditableCell(
                      "date",
                      <span className="font-mono">{r.date?.isoDate ?? "—"}</span>,
                      {
                        inputType: "date",
                        className: `${
                          (r.date?.confidence ?? 1) < CONFIDENCE_THRESHOLDS.date
                            ? "bg-amber-100/40"
                            : ""
                        }`,
                      }
                    )}

                    {/* Merchant */}
                    {renderEditableCell(
                      "merchant",
                      <span className="font-semibold text-black inline-flex items-center gap-1.5">
                        {r.merchant?.name || "—"}
                        {isDemoReceipt && (
                          <span
                            data-testid={`demo-badge-${r.id}`}
                            title={
                              isDe
                                ? "Beispiel-Beleg mit erfundenen Daten — nur zur Vorschau, kein echter Scan"
                                : "Sample receipt with fabricated data — for preview only, not a real scan"
                            }
                            className="shrink-0 border border-amber-300 bg-amber-100 px-1 py-0.5 font-mono text-[9px] font-bold uppercase tracking-caps text-amber-800"
                          >
                            {isDe ? "Demo" : "Demo"}
                          </span>
                        )}
                      </span>,
                      {
                        className: `${
                          (r.merchant?.confidence ?? 1) < CONFIDENCE_THRESHOLDS.merchant
                            ? "bg-amber-100/40"
                            : ""
                        }`,
                      }
                    )}

                    {/* Category Select */}
                    <td
                      onClick={(e) => e.stopPropagation()}
                      className="py-1.5 px-2.5 border-r border-[#E2E8F0]"
                    >
                      <select
                        data-testid={`category-select-${r.id}`}
                        value={r.suggestedCategory || "Sonstiges"}
                        disabled={readOnly}
                        onChange={(event) =>
                          commitValue(r, "category", event.target.value)
                        }
                        className="w-full bg-[#F8FAFC] border border-[#E2E8F0] px-2 py-1 text-xs text-[#161C22] focus:border-black focus:outline-none transition-colors disabled:opacity-70 disabled:cursor-default"
                      >
                        {CATEGORIES.map((cat) => (
                          <option key={cat} value={cat}>
                            {isDe ? CATEGORY_LABELS[cat]?.de || cat : CATEGORY_LABELS[cat]?.en || cat}
                          </option>
                        ))}
                      </select>
                    </td>

                    {/* Payment Method Select */}
                    <td
                      onClick={(e) => e.stopPropagation()}
                      className="py-1.5 px-2.5 border-r border-[#E2E8F0]"
                    >
                      <select
                        data-testid={`payment-select-${r.id}`}
                        value={r.paymentMethod || "SONSTIGE"}
                        disabled={readOnly}
                        onChange={(event) =>
                          commitValue(r, "paymentMethod", event.target.value)
                        }
                        className="w-full bg-[#F8FAFC] border border-[#E2E8F0] px-2 py-1 font-mono text-[11px] text-[#475569] focus:border-black focus:outline-none transition-colors disabled:opacity-70 disabled:cursor-default"
                      >
                        {PAYMENT_METHODS.map((pm) => (
                          <option key={pm.value} value={pm.value}>
                            {isDe ? pm.labelDe : pm.labelEn}
                          </option>
                        ))}
                      </select>
                    </td>

                    {/* Doc Type Select */}
                    <td
                      onClick={(e) => e.stopPropagation()}
                      className="py-1.5 px-2.5 border-r border-[#E2E8F0]"
                    >
                      <select
                        data-testid={`doctype-select-${r.id}`}
                        value={r.documentType || "SONSTIGES"}
                        disabled={readOnly}
                        onChange={(event) =>
                          commitValue(r, "docType", event.target.value)
                        }
                        className="w-full bg-[#F8FAFC] border border-[#E2E8F0] px-2 py-1 font-mono text-[11px] text-[#475569] uppercase focus:border-black focus:outline-none transition-colors disabled:opacity-70 disabled:cursor-default"
                      >
                        {DOC_TYPES.map((type) => (
                          <option key={type} value={type}>
                            {isDe ? DOC_TYPE_LABELS[type]?.de || type : DOC_TYPE_LABELS[type]?.en || type}
                          </option>
                        ))}
                      </select>
                    </td>

                    {/* Receipt Number */}
                    {renderEditableCell(
                      "receiptNumber",
                      <span className="font-mono text-[#64748B]">{r.receiptNumber || "—"}</span>
                    )}

                    {/* Net Amount */}
                    {renderEditableCell(
                      "net",
                      <span data-testid={`net-${r.id}`}>{formatMoney(net, currency)}</span>,
                      { className: "font-mono", align: "right" }
                    )}

                    {/* Tax Rates */}
                    {taxRates.map((rate) => {
                      const amount = taxAmountForRate(r, rate);
                      return (
                        <React.Fragment key={rate}>
                          {renderEditableCell(
                            `${TAX_FIELD_PREFIX}${rate}`,
                            <span data-testid={`tax-${rate}-${r.id}`}>
                              {amount === null ? "—" : formatMoney(amount, currency)}
                            </span>,
                            { className: "font-mono text-[#475569]", align: "right" }
                          )}
                        </React.Fragment>
                      );
                    })}

                    {/* Gross Total */}
                    {renderEditableCell(
                      "gross",
                      <span data-testid={`gross-${r.id}`}>{formatMoney(gross, currency)}</span>,
                      {
                        className: `font-mono font-bold text-black ${
                          (r.totalAmount?.confidence ?? 1) <
                          CONFIDENCE_THRESHOLDS.totalAmount
                            ? "bg-amber-100/50"
                            : ""
                        }`,
                        align: "right",
                      }
                    )}

                    {/* Status Badge */}
                    <td
                      data-testid={`status-${r.id}`}
                      onClick={(e) => {
                        e.stopPropagation();
                        // Open inspector modal to review specific issues, never blindly auto-confirm
                        onViewDetails(r);
                      }}
                      className="py-2 px-3 text-center border-r border-[#E2E8F0] cursor-pointer hover:bg-[#F8FAFC] transition-colors"
                      title={isDe ? "Klicken, um Belegdetails & Prüfhinweise im Reviewer zu öffnen" : "Click to open receipt details & audit notes in reviewer"}
                    >
                      <StatusBadge
                        receipt={r}
                        size="sm"
                        testId={`status-badge-row-${r.id}`}
                        className="cursor-pointer"
                      />
                    </td>

                    {/* Actions */}
                    <td
                      onClick={(e) => e.stopPropagation()}
                      className="py-2.5 px-3 text-center"
                    >
                      <div className="flex items-center justify-center gap-1.5">
                        <button
                          type="button"
                          onClick={() =>
                            setOpenPanelId((prev) => (prev === r.id ? null : r.id))
                          }
                          data-testid={`toggle-panel-${r.id}`}
                          className={`p-1 transition-colors ${
                            isPanelOpen
                              ? "bg-black text-white"
                              : "text-[#475569] hover:bg-[#EEF4FC] hover:text-black"
                          }`}
                          title={isDe ? "Inline Bild-Vorschau & Korrektur" : "Inline image preview & quick edit"}
                        >
                          <ImageIcon className="w-4 h-4" />
                        </button>
                        <button
                          type="button"
                          onClick={() => onViewDetails(r)}
                          data-testid={`inspect-btn-${r.id}`}
                          className="p-1 text-[#475569] transition-colors hover:bg-[#EEF4FC] hover:text-black"
                          title={isDe ? "Side-by-Side Belegprüfer öffnen" : "Open side-by-side receipt reviewer"}
                        >
                          <Eye className="w-4 h-4" />
                        </button>
                        {!readOnly && (
                          <button
                            type="button"
                            onClick={() => onDeleteReceipt(r.id)}
                            data-testid={`delete-${r.id}`}
                            className="p-1 text-red-400 transition-colors hover:bg-red-50 hover:text-red-600"
                            title={isDe ? "Beleg löschen" : "Delete receipt"}
                          >
                            <Trash2 className="w-4 h-4" />
                          </button>
                        )}
                      </div>
                    </td>
                  </tr>

                  {/* Inline Preview Panel */}
                  {isPanelOpen && (
                    <tr className="bg-[#F8FAFC]">
                      <td colSpan={columnCount} className="border-t border-black p-0">
                        <CorrectionPanel
                          receipt={r}
                          currency={currency}
                          taxRates={taxRates}
                          issues={r.validation?.issues ?? []}
                          isDe={isDe}
                          readOnly={readOnly}
                          onCommit={(field, value) => commitValue(r, field, value)}
                          onConfirm={() => {
                            onUpdateReceipt({
                              ...confirmReceiptReviewed(r),
                              updatedAt: new Date().toISOString(),
                            });
                          }}
                          onClose={() => setOpenPanelId(null)}
                          onOpenDetails={() => onViewDetails(r)}
                        />
                      </td>
                    </tr>
                  )}
                </React.Fragment>
              );
            })}
          </tbody>
        </table>
      </div>

      {/* Floating Batch Action Bar */}
      {!readOnly && (
        <BatchActionBar
          selectedIds={selectedIds}
          receipts={receipts}
          onBulkDelete={handleBulkDelete}
          onBulkCategorize={handleBulkCategorize}
          onBulkStatusUpdate={handleBulkStatusUpdate}
          onBulkExport={externalBulkExport}
          projects={projects}
          onBulkMoveToProject={onBulkMoveToProject}
          onClearSelection={clearSelection}
        />
      )}
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Correction Panel Component                                         */
/* ------------------------------------------------------------------ */

interface CorrectionPanelProps {
  receipt: ProcessedReceipt;
  currency: string;
  taxRates: number[];
  issues: Array<{ field: string; severity: string; message: string }>;
  isDe?: boolean;
  readOnly?: boolean;
  onCommit: (field: string, value: string) => void;
  onConfirm: () => void;
  onClose: () => void;
  onOpenDetails: () => void;
}

function CorrectionPanel({
  receipt,
  currency,
  taxRates,
  issues,
  isDe = false,
  readOnly = false,
  onCommit,
  onConfirm,
  onClose,
  onOpenDetails,
}: CorrectionPanelProps) {
  const needsAttention = receiptNeedsAttention(receipt);
  const errorCount = issues.filter((issue) => issue.severity === "error").length;
  const warningCount = issues.length - errorCount;

  return (
    <div className="grid grid-cols-1 gap-6 p-5 lg:grid-cols-12 border-b border-[#E2E8F0]">
      {/* Receipt Image Preview */}
      <div className="lg:col-span-5">
        <div className="mb-2 flex items-center justify-between gap-2">
          <span className="font-mono text-[10px] uppercase tracking-caps font-bold text-black">
            {isDe ? "Beleg-Bild" : "Receipt Image"}
          </span>
          <div className="flex items-center gap-3">
            {receipt.previewUrl && (
              <button
                type="button"
                data-testid={`download-image-${receipt.id}`}
                onClick={() => downloadReceiptImage(receipt)}
                className="font-mono text-[10px] uppercase tracking-caps text-[#475569] underline hover:text-black"
              >
                <Download className="mr-1 inline h-3 w-3" />
                {isDe ? "Bild herunterladen" : "Download image"}
              </button>
            )}
            <button
              type="button"
              onClick={onOpenDetails}
              className="font-mono text-[10px] uppercase tracking-caps text-[#475569] underline hover:text-black"
            >
              {isDe ? "Im Side-by-Side Reviewer öffnen ↗" : "Open in Side-by-Side Reviewer ↗"}
            </button>
          </div>
        </div>
        <div className="flex min-h-[220px] items-center justify-center border border-[#E2E8F0] bg-white p-2">
          {receipt.previewUrl ? (
            // eslint-disable-next-line @next/next/no-img-element
            <img
              src={receipt.previewUrl}
              alt={receipt.originalFileName || (isDe ? "Beleg" : "Receipt")}
              data-testid={`panel-image-${receipt.id}`}
              className="max-h-[320px] w-auto border border-[#E2E8F0] object-contain cursor-pointer"
              onClick={onOpenDetails}
            />
          ) : (
            <div className="p-6 text-center text-[#94A3B8]">
              <FileSpreadsheet className="mx-auto mb-2 h-8 w-8 opacity-40 text-black" />
              <p className="font-mono text-[11px]">{isDe ? "Keine Bildvorschau verfügbar" : "No image preview available"}</p>
            </div>
          )}
        </div>
        <p className="mt-1.5 font-mono text-[10px] text-[#94A3B8] truncate">
          {receipt.originalFileName || receipt.id}
        </p>
      </div>

      {/* Issues & Quick Field Correction */}
      <div className="space-y-4 lg:col-span-7">
        <div className="flex items-start justify-between gap-3">
          <div>
            <span className="font-mono text-[10px] uppercase tracking-caps font-bold text-black">
              {isDe ? "Korrektur & Prüfung" : "Correction & Review"}
            </span>
            <p className="mt-0.5 font-mono text-[10px] text-[#64748B]">
              {needsAttention
                ? (isDe ? `${errorCount} Fehler · ${warningCount} Hinweise` : `${errorCount} errors · ${warningCount} warnings`)
                : receipt.validation?.userConfirmed
                ? (isDe ? "Vom Benutzer verifiziert" : "Verified by user")
                : (isDe ? "Keine rechnerischen Abweichungen" : "No mathematical discrepancies")}
            </p>
          </div>
          <button
            type="button"
            onClick={onClose}
            className="border border-[#E2E8F0] p-1 text-[#475569] hover:border-black hover:text-black"
            aria-label={isDe ? "Korrekturbereich schließen" : "Close correction panel"}
          >
            <X className="h-3.5 w-3.5" />
          </button>
        </div>

        {issues.length > 0 && (
          <ul
            data-testid={`panel-issues-${receipt.id}`}
            className="space-y-1.5 border border-[#E2E8F0] bg-white p-3"
          >
            {issues.map((issue, index) => (
              <li key={index} className="flex items-start gap-2 text-[11px]">
                <span
                  className={`mt-0.5 shrink-0 px-1.5 font-mono text-[9px] uppercase ${
                    issue.severity === "error"
                      ? "bg-[#FFDAD6] text-[#93000A]"
                      : "bg-[#FDE68A] text-[#92400E]"
                  }`}
                >
                  {issue.severity === "error" ? (isDe ? "Fehler" : "Error") : (isDe ? "Hinweis" : "Warning")}
                </span>
                <span className="text-black">{issue.message}</span>
              </li>
            ))}
          </ul>
        )}

        <div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
          <PanelField
            label={isDe ? "Datum" : "Date"}
            type="date"
            value={receipt.date?.isoDate ?? ""}
            readOnly={readOnly}
            onCommit={(value) => onCommit("date", value)}
          />
          <PanelField
            label={isDe ? "Händler" : "Merchant"}
            value={receipt.merchant?.name ?? ""}
            className="col-span-2"
            readOnly={readOnly}
            onCommit={(value) => onCommit("merchant", value)}
          />
          <PanelField
            label={`${isDe ? "Brutto" : "Gross"} (${currency})`}
            value={formatAmountInput(grossOf(receipt))}
            testId={`panel-gross-${receipt.id}`}
            strong
            readOnly={readOnly}
            onCommit={(value) => onCommit("gross", value)}
          />
          <PanelField
            label={`${isDe ? "Netto" : "Net"} (${currency})`}
            value={formatAmountInput(netOf(receipt))}
            testId={`panel-net-${receipt.id}`}
            readOnly={readOnly}
            onCommit={(value) => onCommit("net", value)}
          />
          {taxRates.map((rate) => (
            <PanelField
              key={rate}
              label={taxRateLabel(rate, isDe)}
              value={formatAmountInput(taxAmountForRate(receipt, rate))}
              testId={`panel-tax-${rate}-${receipt.id}`}
              readOnly={readOnly}
              onCommit={(value) => onCommit(`${TAX_FIELD_PREFIX}${rate}`, value)}
            />
          ))}
        </div>

        {!readOnly && (
          <div className="flex flex-wrap items-center gap-2 border-t border-[#E2E8F0] pt-3">
            <button
              type="button"
              onClick={onConfirm}
              disabled={!needsAttention}
              data-testid={`panel-confirm-${receipt.id}`}
              className="flex items-center gap-1.5 bg-black px-3.5 py-1.5 font-mono text-[11px] uppercase tracking-caps text-white transition-colors hover:bg-[#334155] disabled:cursor-not-allowed disabled:opacity-40"
            >
              <UserCheck className="h-3.5 w-3.5" />
              <span>{isDe ? "Als geprüft markieren" : "Mark as Reviewed"}</span>
            </button>
            <span className="font-mono text-[10px] text-[#64748B]">
              {isDe
                ? "Übernimmt den Beleg unverändert – die Rechenprüfung bleibt dokumentiert."
                : "Confirms receipt as-is — math verification audit remains documented."}
            </span>
          </div>
        )}
      </div>
    </div>
  );
}

interface PanelFieldProps {
  label: string;
  value: string;
  type?: string;
  className?: string;
  strong?: boolean;
  testId?: string;
  readOnly?: boolean;
  onCommit: (value: string) => void;
}

function PanelField({
  label,
  value,
  type = "text",
  className = "",
  strong = false,
  testId,
  readOnly = false,
  onCommit,
}: PanelFieldProps) {
  const [draft, setDraft] = useState(value);
  const [dirty, setDirty] = useState(false);

  if (!dirty && draft !== value) {
    setDraft(value);
  }

  const commit = () => {
    setDirty(false);
    if (draft !== value) onCommit(draft);
  };

  return (
    <label className={`block ${className}`}>
      <span className="mb-1 block font-mono text-[9px] uppercase tracking-caps text-[#64748B]">
        {label}
      </span>
      <input
        type={type}
        value={draft}
        data-testid={testId}
        readOnly={readOnly}
        onChange={(event) => {
          if (readOnly) return;
          setDirty(true);
          setDraft(event.target.value);
        }}
        onBlur={commit}
        onKeyDown={(event) => {
          if (readOnly) return;
          if (event.key === "Enter") {
            event.preventDefault();
            commit();
            (event.target as HTMLInputElement).blur();
          } else if (event.key === "Escape") {
            event.preventDefault();
            setDirty(false);
            setDraft(value);
          }
        }}
        className={`w-full border border-[#E2E8F0] bg-white px-2 py-1.5 font-mono text-xs text-black focus:border-black focus:outline-none ${
          strong ? "font-bold" : ""
        } ${readOnly ? "cursor-default bg-[#F8FAFC]" : ""}`}
      />
    </label>
  );
}
