import { useEffect, useMemo, useState } from "react";
import SectionCard from "../components/SectionCard";
import { api, downloadBinary, openBinary } from "../lib/api";

const currentYear = new Date().getFullYear();

function emptyProjectForm(year = currentYear) {
  return {
    project_code: "",
    name: "",
    description: "",
    status: "aktiv",
    calculation_mode: "sum_only",
    committee_id: "",
    project_budget_amount: "0.00",
    annual_budget_amount: "0.00",
    annual_budget_year: String(year),
  };
}

function emptyExpenseLine() {
  return {
    description: "",
    tax_code_id: "",
    tax_code_key: "",
    tax_rate_percent: "0",
    net_amount: "0.00",
  };
}

function emptyExpenseForm(projectId = "") {
  return {
    project_id: projectId,
    expense_date: new Date().toISOString().slice(0, 10),
    title: "",
    vendor: "",
    currency: "EUR",
    payment_status: "offen",
    notes: "",
    lines: [emptyExpenseLine()],
  };
}

function asNumber(value) {
  const parsed = Number(value || 0);
  return Number.isFinite(parsed) ? parsed : 0;
}

function money(value, currency = "EUR") {
  return new Intl.NumberFormat("de-DE", { style: "currency", currency }).format(asNumber(value));
}

function percent(value) {
  return `${new Intl.NumberFormat("de-DE", { maximumFractionDigits: 3 }).format(asNumber(value))} %`;
}

function dateOnly(value) {
  if (!value) return "";
  return String(value).slice(0, 10);
}

function modeLabel(mode) {
  if (mode === "project_budget") return "Projektbudget";
  if (mode === "annual_budget") return "Jahresbudget";
  return "Nur Summe";
}

function statusLabel(status) {
  const labels = {
    aktiv: "Aktiv",
    pausiert: "Pausiert",
    abgeschlossen: "Abgeschlossen",
    archiviert: "Archiviert",
    geplant: "Geplant",
    offen: "Offen",
    bezahlt: "Bezahlt",
    storniert: "Storniert",
  };
  return labels[status] || status;
}

function isAutoGeneratedProjectCode(value) {
  return new RegExp("^FIN-\\d{4}-\\d+$").test(String(value || "").trim());
}

function projectToForm(project, year) {
  return {
    project_code: project.project_code || "",
    name: project.name || "",
    description: project.description || "",
    status: project.status || "aktiv",
    calculation_mode: project.calculation_mode || "sum_only",
    committee_id: project.committee_id || "",
    project_budget_amount: String(project.project_budget_amount || "0.00"),
    annual_budget_amount: String(project.annual_budget_amount || "0.00"),
    annual_budget_year: String(project.annual_budget_year || year || currentYear),
  };
}

function legacyExpenseLine(expense) {
  return {
    description: expense.cost_category || expense.title || "Rechnungsposition",
    tax_code_id: "",
    tax_code_key: expense.cost_category || "",
    tax_rate_percent: String(expense.tax_rate_percent || "0"),
    net_amount: String(expense.net_amount || "0.00"),
  };
}

function expenseToForm(expense) {
  const sourceLines = Array.isArray(expense.lines) && expense.lines.length
    ? expense.lines.map((line) => ({
        id: line.id || undefined,
        description: line.description || "",
        tax_code_id: line.tax_code_id || "",
        tax_code_key: line.tax_code_key || "",
        tax_rate_percent: String(line.tax_rate_percent || "0"),
        net_amount: String(line.net_amount || "0.00"),
      }))
    : [legacyExpenseLine(expense)];

  return {
    project_id: expense.project_id || "",
    expense_date: dateOnly(expense.expense_date),
    title: expense.title || "",
    vendor: expense.vendor || "",
    currency: expense.currency || "EUR",
    payment_status: expense.payment_status || "offen",
    notes: expense.notes || "",
    lines: sourceLines,
  };
}

function lineTaxCode(line, taxCodes) {
  return (taxCodes || []).find((item) => String(item.id) === String(line.tax_code_id));
}

function lineAmounts(line, taxCodes) {
  const taxCode = lineTaxCode(line, taxCodes);
  const rate = asNumber(taxCode?.tax_rate_percent ?? line.tax_rate_percent);
  const net = asNumber(line.net_amount);
  const tax = Math.round((net * rate / 100) * 100) / 100;
  const gross = Math.round((net + tax) * 100) / 100;
  return { net, rate, tax, gross };
}

function sumLines(lines, taxCodes) {
  return (lines || []).reduce(
    (acc, line) => {
      const amounts = lineAmounts(line, taxCodes);
      acc.net += amounts.net;
      acc.tax += amounts.tax;
      acc.gross += amounts.gross;
      return acc;
    },
    { net: 0, tax: 0, gross: 0 }
  );
}

export default function FinancePage() {
  const [meta, setMeta] = useState({ tax_rates: [0, 7, 19], tax_codes: [], payment_statuses: [], calculation_modes: [], committees: [], years: [] });
  const [projects, setProjects] = useState([]);
  const [expenses, setExpenses] = useState([]);
  const [filterYear, setFilterYear] = useState(currentYear);
  const [selectedProjectId, setSelectedProjectId] = useState("");
  const [projectForm, setProjectForm] = useState(() => emptyProjectForm(currentYear));
  const [expenseForm, setExpenseForm] = useState(() => emptyExpenseForm(""));
  const [editingProjectId, setEditingProjectId] = useState("");
  const [projectModalOpen, setProjectModalOpen] = useState(false);
  const [projectCodeLoading, setProjectCodeLoading] = useState(false);
  const [editingExpenseId, setEditingExpenseId] = useState("");
  const [receiptFile, setReceiptFile] = useState(null);
  const [message, setMessage] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const taxCodes = meta.tax_codes || [];

  async function loadMeta() {
    try {
      const data = await api.get("/finance/meta");
      setMeta(data || { tax_rates: [0, 7, 19], tax_codes: [], payment_statuses: [], calculation_modes: [], committees: [], years: [] });
    } catch (err) {
      setError(err.message || "Finanz-Stammdaten konnten nicht geladen werden.");
    }
  }

  async function loadData() {
    setLoading(true);
    setError("");
    try {
      const projectRows = await api.get(`/finance/projects?year=${encodeURIComponent(filterYear)}`);
      const params = new URLSearchParams();
      if (filterYear) params.set("year", String(filterYear));
      if (selectedProjectId) params.set("project_id", String(selectedProjectId));
      const expenseRows = await api.get(`/finance/expenses?${params.toString()}`);
      setProjects(projectRows || []);
      setExpenses(expenseRows || []);
    } catch (err) {
      setError(err.message || "Finanzdaten konnten nicht geladen werden.");
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    loadMeta();
  }, []);

  useEffect(() => {
    loadData();
  }, [filterYear, selectedProjectId]);

  const yearOptions = useMemo(() => {
    const set = new Set([currentYear, Number(filterYear), ...(meta.years || []).map(Number)]);
    return Array.from(set).filter(Boolean).sort((a, b) => b - a);
  }, [meta.years, filterYear]);

  const selectedProject = useMemo(
    () => projects.find((project) => String(project.id) === String(selectedProjectId)),
    [projects, selectedProjectId]
  );

  const totals = useMemo(() => {
    return expenses.reduce(
      (acc, expense) => {
        if (expense.payment_status === "storniert") return acc;
        acc.net += asNumber(expense.net_amount);
        acc.tax += asNumber(expense.tax_amount);
        acc.gross += asNumber(expense.gross_amount);
        return acc;
      },
      { net: 0, tax: 0, gross: 0 }
    );
  }, [expenses]);

  const globalBudget = useMemo(() => {
    return projects.reduce(
      (acc, project) => {
        if (project.calculation_mode === "sum_only") return acc;
        acc.budget += asNumber(project.active_budget_amount);
        acc.spent += asNumber(project.active_spent_amount);
        acc.remaining += asNumber(project.active_remaining_amount);
        return acc;
      },
      { budget: 0, spent: 0, remaining: 0 }
    );
  }, [projects]);

  const expenseTotals = useMemo(() => sumLines(expenseForm.lines, taxCodes), [expenseForm.lines, taxCodes]);

  function updateProjectField(field, value) {
    setProjectForm((prev) => ({ ...prev, [field]: value }));
  }

  function updateExpenseField(field, value) {
    setExpenseForm((prev) => ({ ...prev, [field]: value }));
  }

  function updateExpenseLine(index, field, value) {
    setExpenseForm((prev) => {
      const lines = [...(prev.lines || [])];
      lines[index] = { ...lines[index], [field]: value };
      if (field === "tax_code_id") {
        const taxCode = taxCodes.find((item) => String(item.id) === String(value));
        lines[index].tax_code_key = taxCode?.code || "";
        lines[index].tax_rate_percent = String(taxCode?.tax_rate_percent || 0);
        if (!lines[index].description && taxCode?.label) lines[index].description = taxCode.label;
      }
      return { ...prev, lines };
    });
  }

  function addExpenseLine() {
    setExpenseForm((prev) => ({ ...prev, lines: [...(prev.lines || []), emptyExpenseLine()] }));
  }

  function removeExpenseLine(index) {
    setExpenseForm((prev) => {
      const next = (prev.lines || []).filter((_, lineIndex) => lineIndex !== index);
      return { ...prev, lines: next.length ? next : [emptyExpenseLine()] };
    });
  }

  async function maybeRegenerateProjectCodeForYear() {
    if (editingProjectId) return;
    if (projectForm.project_code && !isAutoGeneratedProjectCode(projectForm.project_code)) return;
    await loadNextProjectCode(projectForm.annual_budget_year || filterYear);
  }

  async function loadNextProjectCode(year = filterYear) {
    setProjectCodeLoading(true);
    try {
      const data = await api.get(`/finance/projects/next-code?year=${encodeURIComponent(year || currentYear)}`);
      const nextCode = data?.project_code || "";
      if (nextCode) {
        setProjectForm((prev) => ({ ...prev, project_code: nextCode }));
      }
      return nextCode;
    } catch (err) {
      setError(err.message || "Projekt-Nr. konnte nicht automatisch erzeugt werden.");
      return "";
    } finally {
      setProjectCodeLoading(false);
    }
  }

  async function openCreateProject() {
    setEditingProjectId("");
    setProjectForm(emptyProjectForm(filterYear));
    setProjectModalOpen(true);
    setMessage("");
    setError("");
    await loadNextProjectCode(filterYear);
  }

  function editProject(project) {
    setEditingProjectId(String(project.id));
    setProjectForm(projectToForm(project, filterYear));
    setProjectModalOpen(true);
    setMessage("");
    setError("");
  }

  function closeProjectModal() {
    setProjectModalOpen(false);
    setEditingProjectId("");
    setProjectForm(emptyProjectForm(filterYear));
  }

  function editExpense(expense) {
    setEditingExpenseId(String(expense.id));
    setExpenseForm(expenseToForm(expense));
    setReceiptFile(null);
    setMessage("");
    setError("");
  }

  function resetExpenseForm() {
    setEditingExpenseId("");
    setExpenseForm(emptyExpenseForm(selectedProjectId || projects[0]?.id || ""));
    setReceiptFile(null);
  }

  async function saveProject(event) {
    event.preventDefault();
    setMessage("");
    setError("");
    try {
      const payload = {
        ...projectForm,
        committee_id: projectForm.committee_id || null,
        project_budget_amount: projectForm.project_budget_amount || 0,
        annual_budget_amount: projectForm.annual_budget_amount || 0,
        annual_budget_year: Number(projectForm.annual_budget_year || filterYear),
      };
      if (editingProjectId) {
        await api.put(`/finance/projects/${editingProjectId}`, payload);
        setMessage("Finanzprojekt gespeichert.");
      } else {
        await api.post("/finance/projects", payload);
        setMessage("Finanzprojekt angelegt.");
      }
      closeProjectModal();
      await loadData();
      await loadMeta();
    } catch (err) {
      setError(err.message || "Finanzprojekt konnte nicht gespeichert werden.");
    }
  }

  async function deleteProject(project) {
    if (!window.confirm(`Finanzprojekt „${project.name}“ archivieren?`)) return;
    setMessage("");
    setError("");
    try {
      await api.delete(`/finance/projects/${project.id}`);
      setMessage("Finanzprojekt archiviert.");
      if (String(selectedProjectId) === String(project.id)) setSelectedProjectId("");
      await loadData();
    } catch (err) {
      setError(err.message || "Finanzprojekt konnte nicht archiviert werden.");
    }
  }

  async function uploadReceipt(expenseId) {
    if (!receiptFile) return;
    const data = new FormData();
    data.append("file", receiptFile);
    data.append("title", `Beleg: ${expenseForm.title}`);
    await api.post(`/finance/expenses/${expenseId}/documents/upload`, data);
  }

  async function saveExpense(event) {
    event.preventDefault();
    setMessage("");
    setError("");

    const validLines = (expenseForm.lines || []).filter((line) => asNumber(line.net_amount) > 0 || line.tax_code_id || line.description);
    if (!validLines.length || validLines.some((line) => !line.tax_code_id)) {
      setError("Bitte für jede Rechnungsposition eine MwSt.-/Kostenart auswählen.");
      return;
    }

    try {
      const payload = {
        project_id: Number(expenseForm.project_id),
        expense_date: expenseForm.expense_date,
        title: expenseForm.title,
        vendor: expenseForm.vendor,
        currency: (expenseForm.currency || "EUR").toUpperCase(),
        payment_status: expenseForm.payment_status,
        notes: expenseForm.notes,
        lines: validLines.map((line) => ({
          description: line.description,
          tax_code_id: Number(line.tax_code_id),
          tax_code_key: line.tax_code_key,
          net_amount: Number(line.net_amount || 0),
        })),
      };

      let saved;
      if (editingExpenseId) {
        saved = await api.put(`/finance/expenses/${editingExpenseId}`, payload);
        setMessage(receiptFile ? "Rechnung und Beleg gespeichert." : "Rechnung gespeichert.");
      } else {
        saved = await api.post("/finance/expenses", payload);
        setMessage(receiptFile ? "Rechnung mit Beleg angelegt." : "Rechnung angelegt.");
      }

      await uploadReceipt(saved.id || editingExpenseId);
      resetExpenseForm();
      await loadData();
      await loadMeta();
    } catch (err) {
      setError(err.message || "Rechnung konnte nicht gespeichert werden.");
    }
  }

  async function deleteExpense(expense) {
    if (!window.confirm(`Rechnung „${expense.title}“ löschen?`)) return;
    setMessage("");
    setError("");
    try {
      await api.delete(`/finance/expenses/${expense.id}`);
      setMessage("Rechnung gelöscht.");
      await loadData();
    } catch (err) {
      setError(err.message || "Rechnung konnte nicht gelöscht werden.");
    }
  }

  return (
    <>
      <style>{`
        .finance-grid { display: grid; gap: 18px; }
        .finance-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
        .finance-kpi { padding: 16px; border-radius: 20px; background: rgba(255,255,255,.78); border: 1px solid rgba(148,164,186,.22); }
        .finance-kpi span { color: var(--muted); display: block; margin-bottom: 6px; }
        .finance-kpi strong { font-size: 1.35rem; }
        .finance-toolbar { display: flex; gap: 10px; align-items: end; flex-wrap: wrap; margin-bottom: 14px; }
        .finance-toolbar label { min-width: 180px; }
        .finance-inline { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
        .finance-mode { display: inline-block; padding: 4px 9px; border-radius: 999px; background: rgba(44,107,237,.10); color: #1d4ed8; font-size: .84rem; font-weight: 700; }
        .finance-danger { color: var(--danger); font-weight: 700; }
        .finance-ok { color: var(--success); font-weight: 700; }
        .receipt-list { display: grid; gap: 6px; }
        .receipt-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
        .finance-code-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
        .finance-budget-box { border: 1px solid rgba(44,107,237,.18); background: #f8fbff; border-radius: 18px; padding: 14px; display: grid; gap: 12px; }
        .finance-budget-box h3 { margin: 0; font-size: 1rem; color: #0f172a; }
        .finance-help { margin: 0; color: var(--muted); font-size: .9rem; line-height: 1.45; }
        .invoice-lines { display: grid; gap: 12px; }
        .invoice-line { border: 1px solid rgba(148,164,186,.26); background: #fff; border-radius: 18px; padding: 14px; display: grid; gap: 12px; }
        .invoice-line-header { display: flex; justify-content: space-between; gap: 12px; align-items: center; }
        .invoice-line-grid { display: grid; grid-template-columns: 1.2fr 1.4fr .7fr; gap: 12px; }
        .invoice-line-sums { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
        .invoice-total-box { padding: 14px; border-radius: 18px; background: #f8fafc; border: 1px solid rgba(148,164,186,.28); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
        .invoice-total-box span, .invoice-line-sums span { color: var(--muted); display: block; font-size: .86rem; }
        .invoice-total-box strong { font-size: 1.15rem; }
        .expense-lines-list { margin: 6px 0 0; padding-left: 18px; color: var(--muted); }
        .finance-modal-backdrop { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; background: rgba(15, 23, 42, 0.62); backdrop-filter: blur(2px); }
        .finance-modal-panel { width: min(820px, 96vw); max-height: min(92vh, 920px); overflow: hidden; display: flex; flex-direction: column; border-radius: 22px; background: #ffffff; color: #0f172a; border: 1px solid rgba(15, 23, 42, 0.12); box-shadow: 0 30px 90px rgba(15, 23, 42, 0.34), 0 8px 24px rgba(15, 23, 42, 0.18); }
        .finance-modal-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 22px 24px 18px; background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%); border-bottom: 1px solid rgba(148, 164, 184, 0.28); }
        .finance-modal-header h2 { margin: 0; color: #0f172a; font-size: 1.35rem; }
        .finance-modal-subtitle { margin: 6px 0 0; color: #64748b; line-height: 1.45; }
        .finance-modal-close { flex: 0 0 auto; width: 36px; height: 36px; border: 1px solid rgba(148, 164, 184, 0.35); border-radius: 999px; background: #ffffff; color: #0f172a; cursor: pointer; font-size: 1.3rem; line-height: 1; box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08); }
        .finance-modal-close:hover { background: #f1f5f9; }
        .finance-modal-body { padding: 22px 24px; overflow: auto; background: #ffffff; }
        .finance-modal-footer { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; padding-top: 4px; }
        @media (max-width: 1100px) { .finance-kpis, .finance-inline, .invoice-line-grid, .invoice-line-sums, .invoice-total-box { grid-template-columns: 1fr; } .finance-modal-backdrop { padding: 12px; align-items: start; } .finance-modal-panel { width: 100%; max-height: calc(100vh - 24px); } }
      `}</style>

      <div className="finance-grid">
        {error ? <div className="alert error">{error}</div> : null}
        {message ? <div className="alert success">{message}</div> : null}

        <SectionCard
          title="Finanzen"
          subtitle="Rechnungen mit mehreren Positionen erfassen, unterschiedliche MwSt.-Sätze verwenden und Kosten auf Projektebene überwachen."
          actions={<div className="row-actions"><button className="btn" type="button" onClick={openCreateProject}>Finanzprojekt anlegen</button><button className="btn secondary" type="button" onClick={loadData} disabled={loading}>{loading ? "Lade…" : "Aktualisieren"}</button></div>}
        >
          <div className="finance-toolbar">
            <label><span>Auswertungsjahr</span><select className="input" value={filterYear} onChange={(event) => setFilterYear(Number(event.target.value))}>{yearOptions.map((year) => <option key={year} value={year}>{year}</option>)}</select></label>
            <label><span>Projektfilter</span><select className="input" value={selectedProjectId} onChange={(event) => setSelectedProjectId(event.target.value)}><option value="">Alle Projekte</option>{projects.map((project) => <option key={project.id} value={project.id}>{project.project_code ? `${project.project_code} · ` : ""}{project.name}</option>)}</select></label>
          </div>

          <div className="finance-kpis">
            <div className="finance-kpi"><span>Rechnungen netto</span><strong>{money(totals.net)}</strong></div>
            <div className="finance-kpi"><span>Steueranteil</span><strong>{money(totals.tax)}</strong></div>
            <div className="finance-kpi"><span>Rechnungen brutto</span><strong>{money(totals.gross)}</strong></div>
            <div className="finance-kpi"><span>Budget Rest</span><strong className={globalBudget.remaining < 0 ? "finance-danger" : "finance-ok"}>{money(globalBudget.remaining)}</strong></div>
          </div>
        </SectionCard>

        <SectionCard title={editingExpenseId ? "Rechnung bearbeiten" : "Rechnung erfassen"} subtitle="Eine Rechnung kann mehrere Positionen mit unterschiedlichen MwSt.-Sätzen enthalten. Die Sätze werden im Adminbereich gepflegt.">
          <form className="form-grid" onSubmit={saveExpense}>
            <label><span>Projekt</span><select required className="input" value={expenseForm.project_id} onChange={(e) => updateExpenseField("project_id", e.target.value)}><option value="">Projekt wählen</option>{projects.map((project) => <option key={project.id} value={project.id}>{project.name}</option>)}</select></label>
            <div className="finance-inline">
              <label><span>Rechnungsdatum</span><input className="input" type="date" required value={expenseForm.expense_date} onChange={(e) => updateExpenseField("expense_date", e.target.value)} /></label>
              <label><span>Status</span><select className="input" value={expenseForm.payment_status} onChange={(e) => updateExpenseField("payment_status", e.target.value)}><option value="geplant">Geplant</option><option value="offen">Offen</option><option value="bezahlt">Bezahlt</option><option value="storniert">Storniert</option></select></label>
            </div>
            <label><span>Rechnungstitel</span><input className="input" required value={expenseForm.title} onChange={(e) => updateExpenseField("title", e.target.value)} /></label>
            <div className="finance-inline">
              <label><span>Lieferant / Empfänger</span><input className="input" value={expenseForm.vendor} onChange={(e) => updateExpenseField("vendor", e.target.value)} /></label>
              <label><span>Währung</span><input className="input" maxLength="3" value={expenseForm.currency} onChange={(e) => updateExpenseField("currency", e.target.value.toUpperCase())} /></label>
            </div>

            <div className="invoice-lines">
              <div className="invoice-line-header">
                <strong>Rechnungspositionen</strong>
                <button className="mini-btn" type="button" onClick={addExpenseLine}>Position hinzufügen</button>
              </div>

              {(expenseForm.lines || []).map((line, index) => {
                const amounts = lineAmounts(line, taxCodes);
                return (
                  <div className="invoice-line" key={index}>
                    <div className="invoice-line-header">
                      <strong>Position {index + 1}</strong>
                      <button className="mini-btn danger" type="button" onClick={() => removeExpenseLine(index)} disabled={(expenseForm.lines || []).length <= 1}>Entfernen</button>
                    </div>
                    <div className="invoice-line-grid">
                      <label><span>Bezeichnung</span><input className="input" value={line.description} onChange={(e) => updateExpenseLine(index, "description", e.target.value)} placeholder="z. B. Bürobedarf" /></label>
                      <label><span>MwSt.-/Kostenart</span><select className="input" required value={line.tax_code_id} onChange={(e) => updateExpenseLine(index, "tax_code_id", e.target.value)}><option value="">Auswählen</option>{taxCodes.map((taxCode) => <option key={taxCode.id} value={taxCode.id}>{taxCode.label} · {percent(taxCode.tax_rate_percent)}</option>)}</select></label>
                      <label><span>Netto</span><input className="input" type="number" min="0" step="0.01" required value={line.net_amount} onChange={(e) => updateExpenseLine(index, "net_amount", e.target.value)} /></label>
                    </div>
                    <div className="invoice-line-sums">
                      <div><span>MwSt.</span><strong>{percent(amounts.rate)}</strong></div>
                      <div><span>Steuer</span><strong>{money(amounts.tax, expenseForm.currency || "EUR")}</strong></div>
                      <div><span>Brutto</span><strong>{money(amounts.gross, expenseForm.currency || "EUR")}</strong></div>
                    </div>
                  </div>
                );
              })}
            </div>

            <div className="invoice-total-box">
              <div><span>Netto gesamt</span><strong>{money(expenseTotals.net, expenseForm.currency || "EUR")}</strong></div>
              <div><span>Steuer gesamt</span><strong>{money(expenseTotals.tax, expenseForm.currency || "EUR")}</strong></div>
              <div><span>Brutto gesamt</span><strong>{money(expenseTotals.gross, expenseForm.currency || "EUR")}</strong></div>
            </div>

            <label><span>Beleg hochladen</span><input className="input" type="file" onChange={(e) => setReceiptFile(e.target.files?.[0] || null)} /></label>
            <label><span>Notizen</span><textarea className="textarea" value={expenseForm.notes} onChange={(e) => updateExpenseField("notes", e.target.value)} /></label>
            <div className="row-actions"><button className="btn" type="submit">{editingExpenseId ? "Rechnung speichern" : "Rechnung anlegen"}</button>{editingExpenseId ? <button className="btn secondary" type="button" onClick={resetExpenseForm}>Abbrechen</button> : null}</div>
          </form>
        </SectionCard>

        <SectionCard title="Projektübersicht" subtitle={`Budgetbetrachtung für ${filterYear}. Bei Projektbudget wird gegen alle Rechnungen gerechnet, bei Jahresbudget nur gegen das ausgewählte Jahr.`}>
          <div className="table-wrap">
            <table className="table">
              <thead><tr><th>Projekt</th><th>Berechnung</th><th>Budget</th><th>Rechnungen</th><th>Rest</th><th>Aktionen</th></tr></thead>
              <tbody>
                {projects.map((project) => {
                  const remaining = project.active_remaining_amount;
                  return (
                    <tr key={project.id}>
                      <td><strong>{project.name}</strong><br /><small>{project.project_code || "ohne Nummer"} · {statusLabel(project.status)}{project.committee_name ? ` · ${project.committee_name}` : ""}</small></td>
                      <td><span className="finance-mode">{modeLabel(project.calculation_mode)}</span><br /><small>{project.expense_count} Rechnungen</small></td>
                      <td>{project.active_budget_amount === null ? "—" : money(project.active_budget_amount)}{project.calculation_mode === "annual_budget" ? <><br /><small>Jahr: {project.annual_budget_year}</small></> : null}</td>
                      <td>{money(project.active_spent_amount)}<br /><small>gesamt: {money(project.gross_total)}</small></td>
                      <td>{remaining === null ? "—" : <span className={asNumber(remaining) < 0 ? "finance-danger" : "finance-ok"}>{money(remaining)}</span>}</td>
                      <td><div className="row-actions"><button className="mini-btn" type="button" onClick={() => { setSelectedProjectId(String(project.id)); setExpenseForm((prev) => ({ ...prev, project_id: String(project.id) })); }}>Filtern</button><button className="mini-btn" type="button" onClick={() => editProject(project)}>Bearbeiten</button><button className="mini-btn danger" type="button" onClick={() => deleteProject(project)}>Archivieren</button></div></td>
                    </tr>
                  );
                })}
                {!projects.length ? <tr><td colSpan="6">Noch keine Finanzprojekte vorhanden.</td></tr> : null}
              </tbody>
            </table>
          </div>
        </SectionCard>

        <SectionCard title="Rechnungen" subtitle={selectedProject ? `Gefiltert auf ${selectedProject.name}` : "Alle Rechnungen im ausgewählten Jahr"}>
          <div className="table-wrap">
            <table className="table">
              <thead><tr><th>Datum</th><th>Rechnung</th><th>Projekt</th><th>Summen</th><th>Status</th><th>Belege</th><th>Aktionen</th></tr></thead>
              <tbody>
                {expenses.map((expense) => (
                  <tr key={expense.id}>
                    <td>{dateOnly(expense.expense_date)}</td>
                    <td><strong>{expense.title}</strong><br /><small>{expense.vendor || "kein Lieferant"}</small>{Array.isArray(expense.lines) && expense.lines.length ? <ul className="expense-lines-list">{expense.lines.map((line) => <li key={line.id || line.line_no}>{line.description} · {percent(line.tax_rate_percent)} · {money(line.gross_amount, expense.currency)}</li>)}</ul> : null}</td>
                    <td>{expense.project_name}</td>
                    <td>{money(expense.net_amount, expense.currency)} netto<br /><small>Steuer {money(expense.tax_amount, expense.currency)}<br />brutto {money(expense.gross_amount, expense.currency)}</small></td>
                    <td>{statusLabel(expense.payment_status)}</td>
                    <td>
                      <div className="receipt-list">
                        {(expense.documents || []).map((doc) => (
                          <div key={doc.id}>
                            <strong>{doc.title}</strong><br /><small>{doc.file_name} · {doc.scan_status}</small>
                            <div className="receipt-actions"><button className="mini-btn" type="button" onClick={() => openBinary(`/finance/documents/${doc.id}/view`)}>Öffnen</button><button className="mini-btn" type="button" onClick={() => downloadBinary(`/finance/documents/${doc.id}/download`, doc.file_name || "beleg")}>Download</button></div>
                          </div>
                        ))}
                        {!(expense.documents || []).length ? <small>Kein Beleg</small> : null}
                      </div>
                    </td>
                    <td><div className="row-actions"><button className="mini-btn" type="button" onClick={() => editExpense(expense)}>Bearbeiten</button><button className="mini-btn danger" type="button" onClick={() => deleteExpense(expense)}>Löschen</button></div></td>
                  </tr>
                ))}
                {!expenses.length ? <tr><td colSpan="7">Keine Rechnungen für die aktuelle Auswahl vorhanden.</td></tr> : null}
              </tbody>
            </table>
          </div>
        </SectionCard>
      </div>

      {projectModalOpen ? (
        <div className="finance-modal-backdrop" onMouseDown={closeProjectModal}>
          <div className="finance-modal-panel" role="dialog" aria-modal="true" aria-labelledby="finance-project-modal-title" onMouseDown={(e) => e.stopPropagation()}>
            <div className="finance-modal-header">
              <div>
                <h2 id="finance-project-modal-title">{editingProjectId ? "Finanzprojekt bearbeiten" : "Finanzprojekt anlegen"}</h2>
                <p className="finance-modal-subtitle">Hier werden Projektbudget und Jahresbudget gepflegt. Das Jahresbudget gilt genau für das unten angegebene Jahr.</p>
              </div>
              <button className="finance-modal-close" type="button" onClick={closeProjectModal} aria-label="Schließen">×</button>
            </div>

            <div className="finance-modal-body">
              <form className="form-grid" onSubmit={saveProject}>
                <div className="finance-inline">
                  <label>
                    <span>Projekt-Nr.</span>
                    <div className="finance-code-row">
                      <input className="input" value={projectForm.project_code} onChange={(e) => updateProjectField("project_code", e.target.value)} placeholder="wird automatisch generiert" />
                      {!editingProjectId ? <button className="mini-btn" type="button" onClick={() => loadNextProjectCode(projectForm.annual_budget_year || filterYear)} disabled={projectCodeLoading}>{projectCodeLoading ? "…" : "Neu"}</button> : null}
                    </div>
                    <small>Format: FIN-{projectForm.annual_budget_year || filterYear}-0001. Die Nummer kann bei Bedarf überschrieben werden.</small>
                  </label>
                  <label><span>Status</span><select className="input" value={projectForm.status} onChange={(e) => updateProjectField("status", e.target.value)}><option value="aktiv">Aktiv</option><option value="pausiert">Pausiert</option><option value="abgeschlossen">Abgeschlossen</option><option value="archiviert">Archiviert</option></select></label>
                </div>
                <label><span>Name</span><input className="input" required value={projectForm.name} onChange={(e) => updateProjectField("name", e.target.value)} /></label>
                <label><span>Berechnungsart</span><select className="input" value={projectForm.calculation_mode} onChange={(e) => updateProjectField("calculation_mode", e.target.value)}>{(meta.calculation_modes || []).map((mode) => <option key={mode.value} value={mode.value}>{mode.label}</option>)}</select></label>

                <div className="finance-budget-box">
                  <h3>Budgetsteuerung</h3>
                  <p className="finance-help">Das Projektbudget ist ein Gesamtbudget für das ganze Projekt. Das Jahresbudget wird separat mit Jahr gespeichert und in der Projektübersicht für das ausgewählte Auswertungsjahr verwendet.</p>
                  <div className="finance-inline">
                    <label><span>Projektbudget gesamt</span><input className="input" type="number" step="0.01" min="0" value={projectForm.project_budget_amount} onChange={(e) => updateProjectField("project_budget_amount", e.target.value)} /></label>
                    <label><span>Jahr für Jahresbudget</span><input className="input" type="number" min="2000" max="2100" value={projectForm.annual_budget_year} onChange={(e) => updateProjectField("annual_budget_year", e.target.value)} onBlur={maybeRegenerateProjectCodeForYear} /></label>
                  </div>
                  <label><span>Jahresbudget für {projectForm.annual_budget_year}</span><input className="input" type="number" step="0.01" min="0" value={projectForm.annual_budget_amount} onChange={(e) => updateProjectField("annual_budget_amount", e.target.value)} /></label>
                </div>

                <div className="finance-inline"><label><span>Ausschuss</span><select className="input" value={projectForm.committee_id} onChange={(e) => updateProjectField("committee_id", e.target.value)}><option value="">Kein Ausschuss</option>{(meta.committees || []).map((committee) => <option key={committee.id} value={committee.id}>{committee.name}</option>)}</select></label></div>
                <label><span>Beschreibung</span><textarea className="textarea" value={projectForm.description} onChange={(e) => updateProjectField("description", e.target.value)} /></label>
                <div className="finance-modal-footer"><button className="btn secondary" type="button" onClick={closeProjectModal}>Abbrechen</button><button className="btn" type="submit">{editingProjectId ? "Projekt speichern" : "Projekt anlegen"}</button></div>
              </form>
            </div>
          </div>
        </div>
      ) : null}
    </>
  );
}
