"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import type { ReactNode } from "react";
import { AlertTriangle, FileCheck2, PackageSearch, Plus, ReceiptText, Send, Trash2, Undo2, XCircle } from "lucide-react";

import ConfirmDialog from "@/components/common/ConfirmDialog";
import { useToast } from "@/components/common/ToastProvider";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { api } from "@/lib/api";
import type {
  InventoryCategory,
  InventoryItem,
} from "@/types/inventory";
import type { LexwareInvoicePreparation } from "@/types/lexware";
import type {
  RepairEstimate,
  RepairEstimateItemType,
  RepairEstimatePayload,
} from "@/types/repair";

const itemTypeLabels: Record<RepairEstimateItemType, string> = {
  labor: "Arbeitszeit",
  part: "Ersatzteil",
  flat_rate: "Pauschale",
  shipping: "Versand",
  other: "Sonstiges",
};

const statusLabels: Record<string, string> = {
  draft: "Entwurf",
  sent: "Gesendet",
  approved: "Freigegeben",
  declined: "Abgelehnt",
  expired: "Abgelaufen",
  cancelled: "Storniert",
  revoked: "Zurückgenommen",
};

function humanizeValidationDetail(detail: unknown): string | null {
  if (!Array.isArray(detail)) {
    return null;
  }

  const messages = detail
    .map((item) => {
      if (typeof item !== "object" || item === null) {
        return null;
      }
      const record = item as { loc?: unknown[]; msg?: unknown };
      const field = Array.isArray(record.loc) ? record.loc.filter((part) => part !== "body").join(".") : "";
      const message = typeof record.msg === "string" ? record.msg : "Ungültiger Wert";
      return field ? `${field}: ${message}` : message;
    })
    .filter((message): message is string => Boolean(message));

  return messages.length ? messages.join(" · ") : null;
}

function getErrorMessage(error: unknown) {
  if (typeof error === "object" && error !== null && "response" in error) {
    const response = (error as { response?: { data?: { detail?: unknown; message?: unknown } } }).response;
    const detailMessage = humanizeValidationDetail(response?.data?.detail);
    if (detailMessage) {
      return detailMessage;
    }
    if (typeof response?.data?.detail === "string") {
      return response.data.detail;
    }
    if (typeof response?.data?.message === "string") {
      return response.data.message;
    }
    return "Bitte prüfe die Eingaben. Mindestens eine gültige Position mit Titel, Menge und Preis ist erforderlich.";
  }
  return "Aktion konnte nicht abgeschlossen werden";
}

function money(cents: number, currency = "EUR") {
  return new Intl.NumberFormat("de-DE", { style: "currency", currency }).format(cents / 100);
}

function dateTime(value: string | null) {
  if (!value) return "-";
  return new Intl.DateTimeFormat("de-DE", { dateStyle: "short", timeStyle: "short" }).format(new Date(value));
}

type EstimateFormItem = {
  item_type: RepairEstimateItemType;
  inventory_item_id: number | null;
  inventory_snapshot_name: string;
  inventory_snapshot_sku: string;
  inventory_snapshot_manufacturer: string | null;
  inventory_snapshot_part_number: string | null;
  inventory_price_overridden: boolean;
  title: string;
  description: string | null;
  quantity: string;
  unit: string;
  unit_price_euros: string;
};

type EstimateFormPayload = Omit<RepairEstimatePayload, "items"> & {
  items: EstimateFormItem[];
};

function parseEuroToCents(value: string): number | null {
  const normalized = value.trim().replace(/\s/g, "").replace(",", ".");
  if (!normalized) {
    return null;
  }
  if (!/^\d+(\.\d{1,2})?$/.test(normalized)) {
    return null;
  }
  return Math.round(Number(normalized) * 100);
}

function centsToEuroInput(cents: number): string {
  return (cents / 100).toFixed(2).replace(".", ",");
}

function emptyItem(): EstimateFormItem {
  return {
    item_type: "labor",
    inventory_item_id: null,
    inventory_snapshot_name: "",
    inventory_snapshot_sku: "",
    inventory_snapshot_manufacturer: null,
    inventory_snapshot_part_number: null,
    inventory_price_overridden: false,
    title: "",
    description: "",
    quantity: "1.00",
    unit: "Std.",
    unit_price_euros: "",
  };
}

function emptyPayload(): EstimateFormPayload {
  return {
    title: "Kostenvoranschlag",
    customer_message: "Bitte prüfen Sie den Kostenvoranschlag und geben Sie uns über den Statuslink Rückmeldung.",
    internal_note: "",
    tax_rate_percent: "19.00",
    currency: "EUR",
    valid_until: null,
    items: [emptyItem()],
  };
}

type Props = {
  repairId: number;
  customerEmail: string;
  canRead: boolean;
  canCreate: boolean;
  canUpdate: boolean;
  canDelete: boolean;
  canSend: boolean;
  canRevoke: boolean;
  canLexwareExport: boolean;
};

export default function RepairEstimatesSection({
  repairId,
  customerEmail,
  canRead,
  canCreate,
  canUpdate,
  canDelete,
  canSend,
  canRevoke,
  canLexwareExport,
}: Props) {
  const { showToast } = useToast();
  const [estimates, setEstimates] = useState<RepairEstimate[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [dialogOpen, setDialogOpen] = useState(false);
  const [editing, setEditing] = useState<RepairEstimate | null>(null);
  const [payload, setPayload] = useState<EstimateFormPayload>(emptyPayload());
  const [saving, setSaving] = useState(false);
  const [pendingId, setPendingId] = useState<number | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<RepairEstimate | null>(null);
  const [cancelTarget, setCancelTarget] = useState<RepairEstimate | null>(null);
  const [revokeTarget, setRevokeTarget] = useState<RepairEstimate | null>(null);
  const [lexwareResult, setLexwareResult] = useState<LexwareInvoicePreparation | null>(null);
  const [lexwareDialogOpen, setLexwareDialogOpen] = useState(false);
  const [inventoryDialogOpen, setInventoryDialogOpen] = useState(false);
  const [inventoryItems, setInventoryItems] = useState<InventoryItem[]>([]);
  const [inventoryCategories, setInventoryCategories] = useState<InventoryCategory[]>([]);
  const [inventorySearch, setInventorySearch] = useState("");
  const [inventoryCategory, setInventoryCategory] = useState("all");
  const [inventoryManufacturer, setInventoryManufacturer] = useState("");
  const [inventoryLoading, setInventoryLoading] = useState(false);
  const [inventoryError, setInventoryError] = useState("");

  const loadEstimates = useCallback(async () => {
    if (!canRead) {
      setLoading(false);
      return;
    }
    setLoading(true);
    setError("");
    try {
      const response = await api.get<RepairEstimate[]>(`/repairs/${repairId}/estimates`);
      setEstimates(response.data);
    } catch (err) {
      setError(getErrorMessage(err));
    } finally {
      setLoading(false);
    }
  }, [canRead, repairId]);

  useEffect(() => {
    queueMicrotask(() => {
      void loadEstimates();
    });
  }, [loadEstimates]);

  const searchInventoryItems = useCallback(async () => {
    setInventoryLoading(true);
    setInventoryError("");
    try {
      const params = new URLSearchParams();
      params.set("limit", "20");
      if (inventorySearch.trim()) params.set("q", inventorySearch.trim());
      if (inventoryCategory !== "all") params.set("category", inventoryCategory);
      if (inventoryManufacturer.trim()) params.set("manufacturer", inventoryManufacturer.trim());
      const [itemsResponse, categoriesResponse] = await Promise.all([
        api.get<InventoryItem[]>(`/inventory/items/search?${params.toString()}`),
        api.get<InventoryCategory[]>("/inventory/categories"),
      ]);
      setInventoryItems(itemsResponse.data);
      setInventoryCategories(categoriesResponse.data);
    } catch (err) {
      setInventoryError(getErrorMessage(err));
    } finally {
      setInventoryLoading(false);
    }
  }, [inventoryCategory, inventoryManufacturer, inventorySearch]);

  useEffect(() => {
    if (!inventoryDialogOpen) {
      return;
    }
    const id = window.setTimeout(() => {
      void searchInventoryItems();
    }, 200);
    return () => window.clearTimeout(id);
  }, [inventoryDialogOpen, searchInventoryItems]);

  const clientSubtotal = useMemo(() => payload.items.reduce((sum, item) => {
    const quantity = Number(item.quantity.replace(",", ".")) || 0;
    const unitPriceCents = parseEuroToCents(item.unit_price_euros) ?? 0;
    return sum + Math.round(quantity * unitPriceCents);
  }, 0), [payload.items]);
  const clientTax = Math.round(clientSubtotal * (Number(payload.tax_rate_percent.replace(",", ".")) || 0) / 100);

  function openCreateDialog() {
    setEditing(null);
    setPayload(emptyPayload());
    setDialogOpen(true);
  }

  function openEditDialog(estimate: RepairEstimate) {
    setEditing(estimate);
    setPayload({
      title: estimate.title,
      customer_message: estimate.customer_message,
      internal_note: estimate.internal_note ?? "",
      tax_rate_percent: String(estimate.tax_rate_percent),
      currency: estimate.currency,
      valid_until: estimate.valid_until,
      items: estimate.items.map((item) => ({
        item_type: item.item_type,
        inventory_item_id: item.inventory_item_id ?? null,
        inventory_snapshot_name: item.inventory_snapshot_name,
        inventory_snapshot_sku: item.inventory_snapshot_sku,
        inventory_snapshot_manufacturer: item.inventory_snapshot_manufacturer,
        inventory_snapshot_part_number: item.inventory_snapshot_part_number,
        inventory_price_overridden: false,
        title: item.title,
        description: item.description ?? "",
        quantity: String(item.quantity),
        unit: item.unit,
        unit_price_euros: centsToEuroInput(item.unit_price_cents),
      })),
    });
    setDialogOpen(true);
  }

  function updateItem(index: number, update: Partial<EstimateFormItem>) {
    setPayload((current) => ({
      ...current,
      items: current.items.map((item, itemIndex) => itemIndex === index ? { ...item, ...update } : item),
    }));
  }

  function addInventoryItem(item: InventoryItem) {
    const formItem: EstimateFormItem = {
      item_type: "part",
      inventory_item_id: item.id,
      inventory_snapshot_name: item.name,
      inventory_snapshot_sku: item.sku,
      inventory_snapshot_manufacturer: item.manufacturer,
      inventory_snapshot_part_number: item.manufacturer_part_number,
      inventory_price_overridden: false,
      title: item.name,
      description: item.description ?? "",
      quantity: "1",
      unit: item.unit,
      unit_price_euros: centsToEuroInput(item.selling_price_cents ?? 0),
    };
    setPayload((current) => ({ ...current, items: [...current.items, formItem] }));
    setInventoryDialogOpen(false);
  }

  async function saveEstimate() {
    setSaving(true);
    try {
      const invalidPriceIndex = payload.items.findIndex((item) => parseEuroToCents(item.unit_price_euros) === null);
      if (invalidPriceIndex >= 0) {
        showToast({
          type: "error",
          title: "Preisangabe ungültig",
          description: `Bitte gib den Einzelpreis in Position ${invalidPriceIndex + 1} als Eurobetrag ein, z. B. 100,00.`,
        });
        return;
      }

      const normalizedPayload = {
        title: payload.title.trim(),
        customer_message: payload.customer_message.trim(),
        internal_note: payload.internal_note?.trim() || null,
        tax_rate_percent: payload.tax_rate_percent.replace(",", "."),
        currency: payload.currency.trim().toUpperCase() || "EUR",
        valid_until: payload.valid_until || null,
        items: payload.items.map((item) => ({
          item_type: item.item_type,
          inventory_item_id: item.inventory_item_id,
          inventory_price_overridden: item.inventory_price_overridden,
          title: item.title.trim(),
          description: item.description?.trim() || null,
          quantity: item.quantity.replace(",", "."),
          unit: item.unit.trim() || "Stk.",
          unit_price_cents: parseEuroToCents(item.unit_price_euros) ?? 0,
        })),
      };
      if (editing) {
        await api.put<RepairEstimate>(`/repairs/${repairId}/estimates/${editing.id}`, normalizedPayload);
      } else {
        await api.post<RepairEstimate>(`/repairs/${repairId}/estimates`, normalizedPayload);
      }
      await loadEstimates();
      setDialogOpen(false);
      showToast({ type: "success", title: editing ? "Kostenvoranschlag gespeichert" : "Kostenvoranschlag erstellt" });
    } catch (err) {
      showToast({ type: "error", title: "Kostenvoranschlag konnte nicht gespeichert werden", description: getErrorMessage(err) });
    } finally {
      setSaving(false);
    }
  }

  async function sendEstimate(estimate: RepairEstimate) {
    setPendingId(estimate.id);
    try {
      await api.post<RepairEstimate>(`/repairs/${repairId}/estimates/${estimate.id}/send`);
      await loadEstimates();
      showToast({ type: "success", title: "Kostenvoranschlag gesendet", description: "Der Versandversuch wurde dokumentiert." });
    } catch (err) {
      showToast({ type: "error", title: "Kostenvoranschlag konnte nicht gesendet werden", description: getErrorMessage(err) });
    } finally {
      setPendingId(null);
    }
  }

  async function cancelEstimate() {
    if (!cancelTarget) return;
    setPendingId(cancelTarget.id);
    try {
      await api.post<RepairEstimate>(`/repairs/${repairId}/estimates/${cancelTarget.id}/cancel`);
      await loadEstimates();
      setCancelTarget(null);
      showToast({ type: "success", title: "Kostenvoranschlag storniert" });
    } catch (err) {
      showToast({ type: "error", title: "Stornierung fehlgeschlagen", description: getErrorMessage(err) });
    } finally {
      setPendingId(null);
    }
  }

  async function revokeEstimate() {
    if (!revokeTarget) return;
    setPendingId(revokeTarget.id);
    try {
      await api.post<RepairEstimate>(`/repairs/${repairId}/estimates/${revokeTarget.id}/revoke`);
      await loadEstimates();
      setRevokeTarget(null);
      showToast({ type: "success", title: "Freigabe zurückgenommen", description: "Die Reservierungen wurden freigegeben." });
    } catch (err) {
      showToast({ type: "error", title: "Freigabe konnte nicht zurückgenommen werden", description: getErrorMessage(err) });
    } finally {
      setPendingId(null);
    }
  }

  async function prepareLexwareInvoice(estimate: RepairEstimate) {
    setPendingId(estimate.id);
    try {
      const response = await api.post<LexwareInvoicePreparation>(`/repairs/${repairId}/estimates/${estimate.id}/lexware/prepare-invoice`);
      setLexwareResult(response.data);
      setLexwareDialogOpen(true);
      showToast({
        type: response.data.ready_for_export ? "success" : "error",
        title: response.data.ready_for_export ? "Lexware-Rechnung vorbereitet" : "Lexware-Vorbereitung mit Hinweisen",
        description: response.data.ready_for_export ? "Die Daten wurden geprüft und für den späteren Export vorgemerkt." : "Bitte prüfe die Hinweise vor dem Export.",
      });
    } catch (err) {
      showToast({ type: "error", title: "Lexware-Rechnung konnte nicht vorbereitet werden", description: getErrorMessage(err) });
    } finally {
      setPendingId(null);
    }
  }

  async function deleteEstimate() {
    if (!deleteTarget) return;
    setPendingId(deleteTarget.id);
    try {
      await api.delete(`/repairs/${repairId}/estimates/${deleteTarget.id}`);
      await loadEstimates();
      setDeleteTarget(null);
      showToast({ type: "success", title: "Kostenvoranschlag gelöscht" });
    } catch (err) {
      showToast({ type: "error", title: "Löschen fehlgeschlagen", description: getErrorMessage(err) });
    } finally {
      setPendingId(null);
    }
  }

  if (!canRead) {
    return <p className="text-sm text-slate-500">Keine Berechtigung für Kostenvoranschläge.</p>;
  }

  if (loading) {
    return <div className="rounded-lg border bg-slate-50 p-5 text-sm text-slate-500">Kostenvoranschläge werden geladen...</div>;
  }

  if (error) {
    return <div className="rounded-lg border bg-red-50 p-5 text-sm text-red-700">{error}</div>;
  }

  return (
    <div className="space-y-4">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <p className="text-sm text-slate-500">{estimates.length} Kostenvoranschlag{estimates.length === 1 ? "" : "e"}</p>
        {canCreate && <Button type="button" onClick={openCreateDialog}><Plus />KV anlegen</Button>}
      </div>

      {estimates.length === 0 ? (
        <div className="rounded-lg border border-dashed bg-slate-50 p-8 text-center">
          <h3 className="text-lg font-semibold text-slate-950">Noch kein Kostenvoranschlag vorhanden.</h3>
          <p className="mx-auto mt-2 max-w-xl text-sm text-slate-500">Erstelle Positionen, lasse Olympus serverseitig summieren und sende den KV per Statuslink an den Kunden.</p>
          {canCreate && <div className="mt-5"><Button type="button" onClick={openCreateDialog}><Plus />KV anlegen</Button></div>}
        </div>
      ) : (
        <div className="grid gap-4 xl:grid-cols-2">
          {estimates.map((estimate) => (
            <article key={estimate.id} className="rounded-lg border bg-white p-5">
              <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
                <div>
                  <div className="flex items-center gap-2">
                    <FileCheck2 className="h-5 w-5 text-slate-500" />
                    <h3 className="font-semibold text-slate-950">{estimate.estimate_number}</h3>
                  </div>
                  <p className="mt-1 text-sm text-slate-600">{estimate.title}</p>
                </div>
                <span className="w-fit rounded-full bg-slate-100 px-2.5 py-1 text-xs font-medium text-slate-700">{statusLabels[estimate.status]}</span>
              </div>

              <dl className="mt-4 grid grid-cols-2 gap-3 text-sm">
                <Meta label="Summe netto" value={money(estimate.subtotal_cents, estimate.currency)} />
                <Meta label="MwSt." value={money(estimate.tax_cents, estimate.currency)} />
                <Meta label="Gesamt" value={money(estimate.total_cents, estimate.currency)} />
                <Meta label="Gültig bis" value={estimate.valid_until ?? "-"} />
                <Meta label="Gesendet" value={dateTime(estimate.sent_at)} />
                <Meta label="Antwort" value={estimate.customer_response_message || "-"} />
              </dl>

              <div className="mt-4 divide-y rounded-lg border">
                {estimate.items.map((item) => (
                  <div key={item.id} className="flex items-start justify-between gap-3 p-3 text-sm">
                    <div>
                      <p className="font-medium text-slate-950">{item.position}. {item.title}</p>
                      <p className="text-xs text-slate-500">
                        {item.inventory_item_id ? `Lagerartikel · ${item.inventory_snapshot_sku} · ` : ""}
                        {itemTypeLabels[item.item_type]} · {item.quantity} {item.unit} × {money(item.unit_price_cents, estimate.currency)}
                      </p>
                      {item.inventory_item_id && (
                        <p className="mt-1 text-xs text-slate-500">
                          {item.inventory_snapshot_manufacturer || "Hersteller nicht angegeben"} · {item.inventory_snapshot_name}
                        </p>
                      )}
                    </div>
                    <p className="font-medium text-slate-950">{money(item.total_cents, estimate.currency)}</p>
                  </div>
                ))}
              </div>

              <div className="mt-4 flex flex-wrap gap-2">
                {canUpdate && ["draft", "sent"].includes(estimate.status) && <Button type="button" variant="outline" size="sm" onClick={() => openEditDialog(estimate)}>Bearbeiten</Button>}
                {canSend && ["draft", "sent"].includes(estimate.status) && <Button type="button" size="sm" onClick={() => void sendEstimate(estimate)} disabled={pendingId === estimate.id || !customerEmail}><Send />Senden</Button>}
                {(canUpdate || canSend) && ["draft", "sent"].includes(estimate.status) && <Button type="button" variant="outline" size="sm" onClick={() => setCancelTarget(estimate)} disabled={pendingId === estimate.id}><XCircle />Stornieren</Button>}
                {canRevoke && estimate.status === "approved" && <Button type="button" variant="destructive" size="sm" onClick={() => setRevokeTarget(estimate)} disabled={pendingId === estimate.id}><Undo2 />Freigabe zurücknehmen</Button>}
                {canLexwareExport && estimate.status === "approved" && <Button type="button" variant="outline" size="sm" onClick={() => void prepareLexwareInvoice(estimate)} disabled={pendingId === estimate.id}><ReceiptText />Lexware-Rechnung vorbereiten</Button>}
                {canDelete && ["draft", "cancelled"].includes(estimate.status) && <Button type="button" variant="destructive" size="sm" onClick={() => setDeleteTarget(estimate)} disabled={pendingId === estimate.id}><Trash2 />Löschen</Button>}
              </div>
            </article>
          ))}
        </div>
      )}

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent className="sm:max-w-4xl">
          <DialogHeader>
            <DialogTitle>{editing ? "Kostenvoranschlag bearbeiten" : "Kostenvoranschlag anlegen"}</DialogTitle>
            <DialogDescription>Summen werden nach dem Speichern serverseitig berechnet.</DialogDescription>
          </DialogHeader>

          <div className="grid max-h-[70vh] gap-5 overflow-y-auto pr-1">
            <div className="grid gap-4 md:grid-cols-2">
              <Field label="Titel"><Input value={payload.title} onChange={(event) => setPayload((current) => ({ ...current, title: event.target.value }))} /></Field>
              <Field label="Gültig bis"><Input type="date" value={payload.valid_until ?? ""} onChange={(event) => setPayload((current) => ({ ...current, valid_until: event.target.value || null }))} /></Field>
              <Field label="MwSt. %"><Input value={payload.tax_rate_percent} onChange={(event) => setPayload((current) => ({ ...current, tax_rate_percent: event.target.value }))} /></Field>
              <Field label="Währung"><Input value={payload.currency} onChange={(event) => setPayload((current) => ({ ...current, currency: event.target.value.toUpperCase() }))} /></Field>
            </div>
            <Field label="Kundennachricht"><textarea className="min-h-20 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-sm outline-none" value={payload.customer_message} onChange={(event) => setPayload((current) => ({ ...current, customer_message: event.target.value }))} /></Field>
            <Field label="Interne Notiz"><textarea className="min-h-20 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-sm outline-none" value={payload.internal_note ?? ""} onChange={(event) => setPayload((current) => ({ ...current, internal_note: event.target.value }))} /></Field>

            <div className="space-y-3">
              <div className="flex items-center justify-between">
                <h4 className="font-semibold text-slate-950">Positionen</h4>
                <div className="flex flex-wrap gap-2">
                  <Button type="button" variant="outline" size="sm" onClick={() => setInventoryDialogOpen(true)}><PackageSearch />Lagerartikel auswählen</Button>
                  <Button type="button" variant="outline" size="sm" onClick={() => setPayload((current) => ({ ...current, items: [...current.items, emptyItem()] }))}><Plus />Position</Button>
                </div>
              </div>
              {payload.items.map((item, index) => (
                <div key={index} className="rounded-lg border bg-slate-50 p-3">
                  {item.inventory_item_id && (
                    <div className="mb-3 flex flex-col gap-2 rounded-lg border bg-white p-3 text-sm text-slate-600 sm:flex-row sm:items-center sm:justify-between">
                      <div>
                        <span className="font-semibold text-slate-950">Lagerartikel</span> · {item.inventory_snapshot_sku} · {item.inventory_snapshot_manufacturer || "Hersteller nicht angegeben"}
                      </div>
                      <label className="flex items-center gap-2 text-xs font-medium text-slate-600">
                        <input type="checkbox" checked={item.inventory_price_overridden} onChange={(event) => updateItem(index, { inventory_price_overridden: event.target.checked })} />
                        Preis manuell überschreiben
                      </label>
                    </div>
                  )}
                  <div className="grid gap-3 md:grid-cols-[1fr_1fr_0.7fr_0.7fr_0.8fr_auto]">
                    <select className="h-8 rounded-lg border border-input bg-white px-2 text-sm" value={item.item_type} disabled={Boolean(item.inventory_item_id)} onChange={(event) => updateItem(index, { item_type: event.target.value as RepairEstimateItemType })}>
                      {Object.entries(itemTypeLabels).map(([value, label]) => <option key={value} value={value}>{label}</option>)}
                    </select>
                    <Input placeholder="Titel" value={item.title} readOnly={Boolean(item.inventory_item_id)} onChange={(event) => updateItem(index, { title: event.target.value })} />
                    <Input placeholder="Menge" value={item.quantity} onChange={(event) => updateItem(index, { quantity: event.target.value })} />
                    <Input placeholder="Einheit" value={item.unit} readOnly={Boolean(item.inventory_item_id)} onChange={(event) => updateItem(index, { unit: event.target.value })} />
                    <Input inputMode="decimal" placeholder="Einzelpreis €" value={item.unit_price_euros} readOnly={Boolean(item.inventory_item_id && !item.inventory_price_overridden)} onChange={(event) => updateItem(index, { unit_price_euros: event.target.value })} />
                    <Button type="button" variant="ghost" size="icon" disabled={payload.items.length === 1} onClick={() => setPayload((current) => ({ ...current, items: current.items.filter((_, itemIndex) => itemIndex !== index) }))} aria-label="Position entfernen"><Trash2 /></Button>
                  </div>
                  <Input className="mt-3" placeholder="Beschreibung optional" value={item.description ?? ""} onChange={(event) => updateItem(index, { description: event.target.value })} />
                </div>
              ))}
            </div>

            <div className="grid gap-3 rounded-lg border bg-slate-50 p-4 text-sm sm:grid-cols-3">
              <Meta label="Netto Vorschau" value={money(clientSubtotal, payload.currency || "EUR")} />
              <Meta label="MwSt. Vorschau" value={money(clientTax, payload.currency || "EUR")} />
              <Meta label="Gesamt Vorschau" value={money(clientSubtotal + clientTax, payload.currency || "EUR")} />
            </div>
          </div>

          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setDialogOpen(false)} disabled={saving}>Abbrechen</Button>
            <Button type="button" onClick={() => void saveEstimate()} disabled={saving}>{saving ? "Speichert..." : "Speichern"}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={inventoryDialogOpen} onOpenChange={setInventoryDialogOpen}>
        <DialogContent className="sm:max-w-4xl">
          <DialogHeader>
            <DialogTitle>Lagerartikel auswählen</DialogTitle>
            <DialogDescription>Aktive Artikel werden als KV-Position übernommen. Preis und Stammdaten werden beim Speichern serverseitig geprüft.</DialogDescription>
          </DialogHeader>

          <div className="grid gap-4">
            <div className="grid gap-3 md:grid-cols-[1fr_220px_180px]">
              <Input placeholder="SKU, Name, Hersteller oder Gerät suchen" value={inventorySearch} onChange={(event) => setInventorySearch(event.target.value)} />
              <select className="h-8 rounded-lg border border-input bg-white px-2 text-sm" value={inventoryCategory} onChange={(event) => setInventoryCategory(event.target.value)}>
                <option value="all">Alle Kategorien</option>
                {inventoryCategories.map((category) => <option key={category.id} value={category.id}>{category.name}</option>)}
              </select>
              <Input placeholder="Hersteller" value={inventoryManufacturer} onChange={(event) => setInventoryManufacturer(event.target.value)} />
            </div>

            {inventoryError ? (
              <p className="rounded-lg border bg-red-50 p-3 text-sm text-red-700">{inventoryError}</p>
            ) : inventoryLoading ? (
              <p className="rounded-lg border bg-slate-50 p-3 text-sm text-slate-500">Lagerartikel werden geladen...</p>
            ) : inventoryItems.length === 0 ? (
              <p className="rounded-lg border bg-slate-50 p-3 text-sm text-slate-500">Keine aktiven Lagerartikel gefunden.</p>
            ) : (
              <div className="max-h-[48vh] divide-y overflow-y-auto rounded-lg border">
                {inventoryItems.map((item) => {
                  const lowAfterSelection = item.quantity_available - 1 <= item.reorder_level;
                  return (
                    <button
                      key={item.id}
                      type="button"
                      className="grid w-full gap-2 p-3 text-left hover:bg-slate-50 md:grid-cols-[1fr_auto]"
                      onClick={() => addInventoryItem(item)}
                    >
                      <div>
                        <p className="font-medium text-slate-950">{item.sku} · {item.name}</p>
                        <p className="text-sm text-slate-500">
                          {item.manufacturer || "Hersteller nicht angegeben"} · Verfügbar {item.quantity_available} {item.unit} · {item.location?.name ?? "Kein Lagerort"}
                        </p>
                        {lowAfterSelection && (
                          <p className="mt-1 inline-flex items-center gap-1 text-xs font-medium text-amber-700">
                            <AlertTriangle size={14} /> Auswahl erreicht oder unterschreitet den Mindestbestand.
                          </p>
                        )}
                      </div>
                      <span className="font-semibold text-slate-950">{money(item.selling_price_cents ?? 0, item.currency)}</span>
                    </button>
                  );
                })}
              </div>
            )}
          </div>

          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setInventoryDialogOpen(false)}>Schließen</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={lexwareDialogOpen} onOpenChange={setLexwareDialogOpen}>
        <DialogContent className="sm:max-w-3xl">
          <DialogHeader>
            <DialogTitle>Lexware-Rechnung vorbereiten</DialogTitle>
            <DialogDescription>Die Rechnung wird noch nicht automatisch in Lexware erstellt.</DialogDescription>
          </DialogHeader>
          {lexwareResult && (
            <div className="grid max-h-[70vh] gap-4 overflow-y-auto pr-1 text-sm">
              <div className={`rounded-lg border p-4 ${lexwareResult.ready_for_export ? "bg-emerald-50 text-emerald-950" : "bg-amber-50 text-amber-950"}`}>
                <p className="font-semibold">{lexwareResult.ready_for_export ? "Bereit für späteren Export" : "Vorbereitung mit Hinweisen"}</p>
                <p className="mt-1">Sync-Record #{lexwareResult.sync_record_id}</p>
              </div>

              {lexwareResult.warnings.length > 0 && (
                <div className="rounded-lg border bg-amber-50 p-4 text-amber-950">
                  <p className="font-semibold">Warnungen</p>
                  <ul className="mt-2 list-disc space-y-1 pl-5">
                    {lexwareResult.warnings.map((warning) => <li key={warning}>{warning}</li>)}
                  </ul>
                </div>
              )}

              <div className="grid gap-3 rounded-lg border bg-slate-50 p-4 md:grid-cols-2">
                <Meta label="Kunde" value={lexwareResult.customer_mapping.name} />
                <Meta label="E-Mail" value={lexwareResult.customer_mapping.email || "-"} />
                <Meta label="Telefon" value={lexwareResult.customer_mapping.phone || "-"} />
                <Meta label="Kontaktabgleich" value={lexwareResult.customer_mapping.search_strategy} />
              </div>

              <div className="rounded-lg border">
                <div className="grid grid-cols-[1fr_auto_auto] gap-3 border-b bg-slate-50 p-3 text-xs font-semibold uppercase text-slate-500">
                  <span>Position</span>
                  <span>Steuer</span>
                  <span>Summe</span>
                </div>
                {lexwareResult.line_item_mapping.map((item, index) => (
                  <div key={`${item.title}-${index}`} className="grid grid-cols-[1fr_auto_auto] gap-3 border-b p-3 last:border-b-0">
                    <div>
                      <p className="font-medium text-slate-950">{item.title}</p>
                      <p className="text-xs text-slate-500">{item.quantity} {item.unit} × {item.unit_price} €</p>
                    </div>
                    <span>{item.tax_rate} %</span>
                    <span className="font-medium text-slate-950">{item.total} €</span>
                  </div>
                ))}
              </div>

              <div className="grid gap-3 rounded-lg border bg-slate-50 p-4 md:grid-cols-3">
                <Meta label="Netto" value={`${String(lexwareResult.payload_summary.subtotal ?? "-")} €`} />
                <Meta label="MwSt." value={`${String(lexwareResult.payload_summary.tax ?? "-")} €`} />
                <Meta label="Gesamt" value={`${String(lexwareResult.payload_summary.total ?? "-")} €`} />
              </div>
            </div>
          )}
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setLexwareDialogOpen(false)}>Schließen</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <ConfirmDialog
        open={Boolean(cancelTarget)}
        title="Kostenvoranschlag stornieren?"
        description="Der Kostenvoranschlag wird storniert. Reservierte Lagerartikel werden freigegeben."
        confirmLabel="Stornieren"
        pending={pendingId === cancelTarget?.id}
        onOpenChange={(open) => !open && setCancelTarget(null)}
        onConfirm={() => void cancelEstimate()}
      >
        {cancelTarget && <p className="text-sm text-slate-600">{cancelTarget.estimate_number} · {cancelTarget.title}</p>}
      </ConfirmDialog>

      <ConfirmDialog
        open={Boolean(revokeTarget)}
        title="Freigabe zurücknehmen?"
        description="Möchten Sie den bereits freigegebenen Kostenvoranschlag wirklich zurücknehmen? Die Lagerreservierungen werden freigegeben und der Kunde erhält eine Benachrichtigung."
        confirmLabel="Freigabe zurücknehmen"
        pending={pendingId === revokeTarget?.id}
        onOpenChange={(open) => !open && setRevokeTarget(null)}
        onConfirm={() => void revokeEstimate()}
      >
        {revokeTarget && <p className="text-sm text-slate-600">{revokeTarget.estimate_number} · {revokeTarget.title}</p>}
      </ConfirmDialog>

      <ConfirmDialog
        open={Boolean(deleteTarget)}
        title="Kostenvoranschlag löschen?"
        description="Der Entwurf wird dauerhaft entfernt."
        pending={pendingId === deleteTarget?.id}
        onOpenChange={(open) => !open && setDeleteTarget(null)}
        onConfirm={() => void deleteEstimate()}
      >
        {deleteTarget && <p className="text-sm text-slate-600">{deleteTarget.estimate_number} · {deleteTarget.title}</p>}
      </ConfirmDialog>
    </div>
  );
}

function Meta({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <dt className="text-xs font-medium uppercase tracking-wide text-slate-500">{label}</dt>
      <dd className="mt-1 break-words font-medium text-slate-950">{value}</dd>
    </div>
  );
}

function Field({ label, children }: { label: string; children: ReactNode }) {
  return (
    <label className="block">
      <span className="mb-1.5 block text-sm font-medium text-slate-700">{label}</span>
      {children}
    </label>
  );
}
