// forms.jsx — modal forms for CRUD on Stammdaten (Properties, Units, Tenants, Transactions)
// Lightweight reusable Modal + form components, registered on window.

function Modal({ open, onClose, title, children, footer, wide }) {
  // Esc closes the modal — preserves the keyboard escape route after we removed
  // backdrop-click-to-close (which dismissed forms accidentally mid-typing).
  React.useEffect(() => {
    if (!open || !onClose) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="upload-modal-backdrop">
      <div className="upload-modal" style={wide ? { maxWidth: 720 } : null}>
        <div className="upload-modal-head">
          <h3>{title}</h3>
          {onClose && <button type="button" className="upload-modal-close" onClick={onClose} aria-label="Schließen">✕</button>}
        </div>
        <div style={{ padding: '8px 24px', overflowY: 'auto', flex: 1 }}>
          {children}
        </div>
        {footer && <div className="upload-modal-actions">{footer}</div>}
      </div>
    </div>
  );
}

// Wrap a form to suppress Enter-submit from single-line inputs.
// Without this, hitting Enter in any text/number input submits the form,
// which closes the modal before the user finishes filling out other fields.
// Textareas still get Enter for line breaks.
const noEnterSubmit = (e) => {
  if (e.key === 'Enter' && e.target.tagName === 'INPUT' && e.target.type !== 'submit') {
    e.preventDefault();
  }
};

function FormField({ label, children, hint, required }) {
  return (
    <div className="upload-modal-field" style={{ borderBottom: 'none', padding: '10px 0' }}>
      <label>{label}{required ? ' *' : ''}</label>
      {children}
      {hint && <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{hint}</div>}
    </div>
  );
}

const PROPERTY_TYPES = ['Mehrfamilienhaus', 'Doppelhaushälfte', 'Einfamilienhaus', 'Eigentumswohnung', 'Gewerbeobjekt', 'Sonstiges'];

function PropertyForm({ open, onClose, store, initial }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const initForm = (i) => ({
    name: i?.name || '',
    address: i?.address || '',
    type: i?.type || 'Mehrfamilienhaus',
    yearBuilt: i?.yearBuilt || '',
    purchaseDate: i?.purchaseDate || '',
    purchasePrice: i?.purchasePrice || '',
    notes: i?.notes || '',
    legalOwnerName: i?.legalOwnerName || '',
    legalOwnerAddress: i?.legalOwnerAddress || '',
    legalOwnerEmail: i?.legalOwnerEmail || '',
    ownerIban: i?.ownerIban || '',
    ownerUstId: i?.ownerUstId || '',
  });
  const [form, setForm] = React.useState(() => initForm(initial));
  // Auto-expand the override section if any field is filled
  const hasOverrides = (i) => !!(i?.legalOwnerName || i?.legalOwnerAddress || i?.legalOwnerEmail || i?.ownerIban || i?.ownerUstId);
  const [showOverride, setShowOverride] = React.useState(() => hasOverrides(initial));
  React.useEffect(() => {
    if (open) { setForm(initForm(initial)); setShowOverride(hasOverrides(initial)); setErr(null); }
  }, [open, initial]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const submit = async (e) => {
    e.preventDefault();
    if (!form.name.trim()) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        name: form.name.trim(),
        address: form.address.trim() || null,
        type: form.type || null,
        yearBuilt: form.yearBuilt ? Number(form.yearBuilt) : null,
        purchaseDate: form.purchaseDate || null,
        purchasePrice: form.purchasePrice ? Number(form.purchasePrice) : null,
        notes: form.notes.trim() || null,
        // Per-property overrides — null means "use global settings"
        legalOwnerName: form.legalOwnerName.trim() || null,
        legalOwnerAddress: form.legalOwnerAddress.trim() || null,
        legalOwnerEmail: form.legalOwnerEmail.trim() || null,
        ownerIban: form.ownerIban.trim() || null,
        ownerUstId: form.ownerUstId.trim() || null,
      };
      if (initial?.id) await store.updateProperty(initial.id, body);
      else await store.addProperty(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Objekt bearbeiten' : 'Neues Objekt'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="property-form" className="btn btn-primary" disabled={busy || !form.name.trim()}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="property-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Name" required>
          <input className="form-input" value={form.name} onChange={e => update('name', e.target.value)} placeholder="z.B. Lindenstraße 42" autoFocus />
        </FormField>
        <FormField label="Adresse">
          <input className="form-input" value={form.address} onChange={e => update('address', e.target.value)} placeholder="Straße, PLZ, Ort" />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Typ">
            <select className="form-input" value={form.type} onChange={e => update('type', e.target.value)}>
              {PROPERTY_TYPES.map(t => <option key={t} value={t}>{t}</option>)}
            </select>
          </FormField>
          <FormField label="Baujahr">
            <input type="number" className="form-input" value={form.yearBuilt} onChange={e => update('yearBuilt', e.target.value)} placeholder="z.B. 1972" />
          </FormField>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Kaufdatum">
            <input type="date" className="form-input" value={form.purchaseDate} onChange={e => update('purchaseDate', e.target.value)} />
          </FormField>
          <FormField label="Kaufpreis (€)">
            <input type="number" className="form-input" value={form.purchasePrice} onChange={e => update('purchasePrice', e.target.value)} placeholder="z.B. 450000" step="1000" />
          </FormField>
        </div>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} placeholder="optional, für dich" />
        </FormField>

        <div style={{ marginTop: 16, paddingTop: 16, borderTop: '1px solid var(--line-2)' }}>
          <button
            type="button"
            onClick={() => setShowOverride(!showOverride)}
            style={{ background: 'none', border: 0, padding: 0, font: 'inherit', cursor: 'pointer', color: 'var(--ink-2)', fontSize: 13, fontWeight: 500 }}
          >
            {showOverride ? '▾' : '▸'} Abweichender Eigentümer / Bank für dieses Objekt
          </button>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4, marginBottom: showOverride ? 12 : 0 }}>
            Standard sind die Werte aus den Einstellungen. Hier überschreiben, wenn dieses Objekt z.B. einer GmbH gehört oder eine andere IBAN nutzt.
          </div>

          {showOverride && (
            <>
              <FormField label="Vermietername (überschreibt Einstellungen)">
                <input className="form-input" value={form.legalOwnerName} onChange={e => update('legalOwnerName', e.target.value)} placeholder="z.B. Tessmann Immobilien GmbH" />
              </FormField>
              <FormField label="Adresse (überschreibt Einstellungen)">
                <textarea className="form-input" rows={2} value={form.legalOwnerAddress} onChange={e => update('legalOwnerAddress', e.target.value)} placeholder="Geschäftsadresse, PLZ, Ort" />
              </FormField>
              <FormField label="E-Mail (überschreibt Einstellungen)">
                <input type="email" className="form-input" value={form.legalOwnerEmail} onChange={e => update('legalOwnerEmail', e.target.value)} />
              </FormField>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                <FormField label="IBAN für dieses Objekt">
                  <input className="form-input" value={form.ownerIban} onChange={e => update('ownerIban', e.target.value)} placeholder="DE…" />
                </FormField>
                <FormField label="USt-IdNr. für dieses Objekt">
                  <input className="form-input" value={form.ownerUstId} onChange={e => update('ownerUstId', e.target.value)} placeholder="DE123456789" />
                </FormField>
              </div>
            </>
          )}
        </div>

        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

const UNIT_STATUSES = [
  { value: 'vermietet', label: 'Vermietet' },
  { value: 'leerstand', label: 'Leerstand' },
  { value: 'kündigung', label: 'In Kündigung' },
];

function UnitForm({ open, onClose, store, propertyId, tenants, initial }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [form, setForm] = React.useState(() => initialUnitForm(initial));
  React.useEffect(() => { if (open) { setForm(initialUnitForm(initial)); setErr(null); } }, [open, initial]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const submit = async (e) => {
    e.preventDefault();
    if (!form.label.trim()) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        propertyId,
        label: form.label.trim(),
        floor: form.floor.trim() || null,
        size: form.size ? Number(form.size) : null,
        rooms: form.rooms ? Number(form.rooms) : null,
        rent: form.rent ? Number(form.rent) : 0,
        status: form.status || 'leerstand',
        tenantId: form.tenantId || null,
        notes: form.notes.trim() || null,
      };
      if (initial?.id) await store.updateUnit(initial.id, body);
      else await store.addUnit(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Wohnung bearbeiten' : 'Neue Wohnung'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="unit-form" className="btn btn-primary" disabled={busy || !form.label.trim()}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="unit-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Bezeichnung" required hint={'z.B. Wohnung 1, Dachgeschoss, Gewerbe EG'}>
          <input className="form-input" value={form.label} onChange={e => update('label', e.target.value)} autoFocus />
        </FormField>
        <FormField label="Etage / Lage">
          <input className="form-input" value={form.floor} onChange={e => update('floor', e.target.value)} placeholder="z.B. 1. OG links" />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Wohnfläche (m²)">
            <input type="number" className="form-input" value={form.size} onChange={e => update('size', e.target.value)} step="0.1" />
          </FormField>
          <FormField label="Zimmer">
            <input type="number" className="form-input" value={form.rooms} onChange={e => update('rooms', e.target.value)} step="0.5" />
          </FormField>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Kaltmiete (€/Monat)">
            <input type="number" className="form-input" value={form.rent} onChange={e => update('rent', e.target.value)} step="10" />
          </FormField>
          <FormField label="Status">
            <select className="form-input" value={form.status} onChange={e => update('status', e.target.value)}>
              {UNIT_STATUSES.map(s => <option key={s.value} value={s.value}>{s.label}</option>)}
            </select>
          </FormField>
        </div>
        <FormField label="Mieter">
          <select className="form-input" value={form.tenantId || ''} onChange={e => update('tenantId', e.target.value)}>
            <option value="">— kein Mieter (Leerstand) —</option>
            {Object.values(tenants || {}).map(t => <option key={t.id} value={t.id}>{t.name}</option>)}
          </select>
        </FormField>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

function initialUnitForm(initial) {
  return {
    label: initial?.label || '',
    floor: initial?.floor || '',
    size: initial?.size || '',
    rooms: initial?.rooms || '',
    rent: initial?.rent || '',
    status: initial?.status || 'leerstand',
    tenantId: initial?.tenantId || initial?.tenant || '',
    notes: initial?.notes || '',
  };
}

function TenantForm({ open, onClose, store, initial }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [form, setForm] = React.useState(() => initialTenantForm(initial));
  React.useEffect(() => { if (open) { setForm(initialTenantForm(initial)); setErr(null); } }, [open, initial]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const submit = async (e) => {
    e.preventDefault();
    if (!form.name.trim()) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        name: form.name.trim(),
        email: form.email.trim() || null,
        phone: form.phone.trim() || null,
        since: form.since || null,
        until: form.until || null,
        deposit: form.deposit ? Number(form.deposit) : null,
        notes: form.notes.trim() || null,
        birthdate: form.birthdate || null,
        addressPrev: form.addressPrev.trim() || null,
        iban: form.iban.trim() || null,
      };
      if (initial?.id) await store.updateTenant(initial.id, body);
      else await store.addTenant(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Mieter bearbeiten' : 'Neuer Mieter'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="tenant-form" className="btn btn-primary" disabled={busy || !form.name.trim()}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="tenant-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Name" required>
          <input className="form-input" value={form.name} onChange={e => update('name', e.target.value)} placeholder="Vor- und Nachname" autoFocus />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="E-Mail">
            <input type="email" className="form-input" value={form.email} onChange={e => update('email', e.target.value)} />
          </FormField>
          <FormField label="Telefon">
            <input type="tel" className="form-input" value={form.phone} onChange={e => update('phone', e.target.value)} />
          </FormField>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Mietbeginn">
            <input type="date" className="form-input" value={form.since} onChange={e => update('since', e.target.value)} />
          </FormField>
          <FormField label="Mietende">
            <input type="date" className="form-input" value={form.until} onChange={e => update('until', e.target.value)} />
          </FormField>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Kaution (€)">
            <input type="number" className="form-input" value={form.deposit} onChange={e => update('deposit', e.target.value)} step="10" />
          </FormField>
          <FormField label="Geburtsdatum">
            <input type="date" className="form-input" value={form.birthdate} onChange={e => update('birthdate', e.target.value)} />
          </FormField>
        </div>
        <FormField label="IBAN">
          <input className="form-input" value={form.iban} onChange={e => update('iban', e.target.value)} placeholder="DE…" />
        </FormField>
        <FormField label="Vorherige Adresse" hint="Optional, für den Mietvertrag">
          <input className="form-input" value={form.addressPrev} onChange={e => update('addressPrev', e.target.value)} placeholder="Straße, PLZ, Ort" />
        </FormField>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

function initialTenantForm(initial) {
  return {
    name: initial?.name || '',
    email: initial?.email || '',
    phone: initial?.phone || '',
    since: initial?.since || '',
    until: initial?.until || '',
    deposit: initial?.deposit || '',
    notes: initial?.notes || '',
    birthdate: initial?.birthdate || '',
    addressPrev: initial?.addressPrev || '',
    iban: initial?.iban || '',
  };
}

const TX_CATEGORIES_INCOME = ['Miete', 'Nebenkostenvorauszahlung', 'Kaution', 'Sonstiges'];
const TX_CATEGORIES_EXPENSE = ['Reparatur', 'Versicherung', 'Grundsteuer', 'Hausgeld', 'Verwaltung', 'Wartung', 'Modernisierung', 'Heizung/Strom', 'Sonstiges'];

function TransactionForm({ open, onClose, store, properties, initial, defaultPropertyId, defaultUnitId, defaultType = 'einnahme' }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const today = new Date().toISOString().slice(0, 10);
  const [form, setForm] = React.useState(() => initialTxForm(initial, defaultPropertyId, defaultUnitId, defaultType, today));
  React.useEffect(() => { if (open) { setForm(initialTxForm(initial, defaultPropertyId, defaultUnitId, defaultType, today)); setErr(null); } }, [open, initial, defaultPropertyId, defaultUnitId, defaultType]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const propUnits = (properties || []).find(p => p.id === form.propertyId)?.units || [];

  const submit = async (e) => {
    e.preventDefault();
    if (!form.date || !form.amount) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        propertyId: form.propertyId || null,
        unitId: form.unitId || null,
        date: form.date,
        type: form.type,
        amount: form.type === 'ausgabe' ? -Math.abs(Number(form.amount)) : Math.abs(Number(form.amount)),
        category: form.category || null,
        description: form.description.trim() || null,
        notes: form.notes.trim() || null,
      };
      if (initial?.id) await store.updateTransaction(initial.id, body);
      else await store.addTransaction(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  const categories = form.type === 'einnahme' ? TX_CATEGORIES_INCOME : TX_CATEGORIES_EXPENSE;

  return (
    <Modal wide open={open} onClose={busy ? null : onClose} title={initial ? 'Buchung bearbeiten' : 'Neue Buchung'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="tx-form" className="btn btn-primary" disabled={busy || !form.date || !form.amount}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="tx-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Art" required>
          <div style={{ display: 'flex', gap: 8 }}>
            <button type="button" className={`btn btn-sm ${form.type === 'einnahme' ? 'btn-primary' : 'btn-ghost'}`} onClick={() => update('type', 'einnahme')}>+ Einnahme</button>
            <button type="button" className={`btn btn-sm ${form.type === 'ausgabe' ? 'btn-primary' : 'btn-ghost'}`} onClick={() => update('type', 'ausgabe')}>− Ausgabe</button>
          </div>
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Datum" required>
            <input type="date" className="form-input" value={form.date} onChange={e => update('date', e.target.value)} />
          </FormField>
          <FormField label="Betrag (€)" required>
            <input type="number" className="form-input" value={form.amount} onChange={e => update('amount', e.target.value)} step="0.01" placeholder="0,00" />
          </FormField>
        </div>
        <FormField label="Objekt">
          <select className="form-input" value={form.propertyId || ''} onChange={e => { update('propertyId', e.target.value); update('unitId', ''); }}>
            <option value="">— kein Objekt —</option>
            {(properties || []).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </FormField>
        {form.propertyId && propUnits.length > 0 && (
          <FormField label="Wohnung">
            <select className="form-input" value={form.unitId || ''} onChange={e => update('unitId', e.target.value)}>
              <option value="">— alle Einheiten / allgemein —</option>
              {propUnits.map(u => <option key={u.id} value={u.id}>{u.label}</option>)}
            </select>
          </FormField>
        )}
        <FormField label="Kategorie">
          <select className="form-input" value={form.category || ''} onChange={e => update('category', e.target.value)}>
            <option value="">— wählen —</option>
            {categories.map(c => <option key={c} value={c}>{c}</option>)}
          </select>
        </FormField>
        <FormField label="Beschreibung">
          <input className="form-input" value={form.description} onChange={e => update('description', e.target.value)} placeholder="z.B. Mieteingang, Klempner Notdienst" />
        </FormField>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>

        {initial?.id && (
          <TransactionReceiptsSection transactionId={initial.id} propertyId={form.propertyId} unitId={form.unitId} />
        )}
        {!initial?.id && (
          <div style={{ marginTop: 12, padding: 12, background: 'var(--bg-sunken)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--ink-3)' }}>
            💡 Belege kannst du nach dem Speichern verknüpfen — diese Buchung dann nochmal öffnen.
          </div>
        )}

        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

// Verknüpfte Belege einer Buchung — wird nur beim Bearbeiten einer existierenden Tx angezeigt.
function TransactionReceiptsSection({ transactionId, propertyId, unitId }) {
  const [linked, setLinked] = React.useState([]);
  const [unlinked, setUnlinked] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [showPicker, setShowPicker] = React.useState(false);
  const [pendingFiles, setPendingFiles] = React.useState(null);
  const inputRef = React.useRef(null);

  const reload = React.useCallback(async () => {
    setLoading(true);
    try {
      const lk = await window.listDocumentsForTransaction(transactionId);
      setLinked(lk);
      // Load all docs to power the "vorhandenes Dokument verknüpfen"-Picker (only the unlinked ones)
      const all = await window.listDocuments({});
      setUnlinked(all.filter(d => !d.transactionId));
    } catch (e) { console.error(e); }
    finally { setLoading(false); }
  }, [transactionId]);

  React.useEffect(() => { reload(); }, [reload]);

  const onUnlink = async (docId) => {
    await window.linkDocumentToTransaction(docId, null);
    reload();
  };
  const onLinkExisting = async (docId) => {
    await window.linkDocumentToTransaction(docId, transactionId);
    setShowPicker(false);
    reload();
  };
  const onPickFile = async (e) => {
    const files = Array.from(e.target.files || []).filter(Boolean);
    if (!files.length) return;
    setPendingFiles(files);
    if (inputRef.current) inputRef.current.value = '';
  };

  return (
    <div style={{ marginTop: 16, paddingTop: 16, borderTop: '1px solid var(--line-2)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
        <div style={{ fontSize: 13, fontWeight: 500 }}>📎 Verknüpfte Belege ({linked.length})</div>
        <div style={{ display: 'flex', gap: 6 }}>
          <button type="button" className="btn btn-sm btn-ghost" onClick={() => inputRef.current?.click()}>↑ Hochladen</button>
          {unlinked.length > 0 && (
            <button type="button" className="btn btn-sm btn-ghost" onClick={() => setShowPicker(!showPicker)}>
              Vorhandenen wählen ({unlinked.length})
            </button>
          )}
        </div>
        <input ref={inputRef} type="file" multiple accept=".pdf,.jpg,.jpeg,.png,.heic" style={{ display: 'none' }} onChange={onPickFile} />
      </div>

      {loading && <div className="muted" style={{ fontSize: 12 }}>Lade…</div>}

      {linked.length === 0 && !loading && (
        <div style={{ padding: 14, background: 'var(--bg-sunken)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--ink-3)', textAlign: 'center' }}>
          Noch kein Beleg verknüpft. Lade einen hoch oder wähle einen vorhandenen.
        </div>
      )}

      {linked.map(doc => (
        <div key={doc.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 8px', background: 'var(--bg-sunken)', borderRadius: 'var(--radius)', marginBottom: 4 }}>
          <span style={{ fontSize: 14 }}>📄</span>
          <a href={window.viewDocumentUrl(doc.id)} target="_blank" rel="noopener" style={{ flex: 1, fontSize: 12.5, color: 'var(--ink)', textDecoration: 'none', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {doc.name}
          </a>
          {doc.category && <span className="pill" style={{ fontSize: 10 }}>{doc.category}</span>}
          <a href={window.downloadDocumentUrl(doc.id)} className="doc-download-btn" download style={{ width: 22, height: 22, fontSize: 12 }}>↓</a>
          <button type="button" className="btn-link" onClick={() => onUnlink(doc.id)} style={{ fontSize: 11, color: 'var(--neg)' }} title="Verknüpfung lösen">✕</button>
        </div>
      ))}

      {showPicker && unlinked.length > 0 && (
        <div style={{ marginTop: 8, padding: 8, border: '1px solid var(--line)', borderRadius: 'var(--radius)', maxHeight: 200, overflowY: 'auto' }}>
          <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em', padding: '4px 8px', marginBottom: 4 }}>Nicht verknüpfte Dokumente</div>
          {unlinked.slice(0, 50).map(doc => (
            <button
              key={doc.id} type="button"
              onClick={() => onLinkExisting(doc.id)}
              style={{ display: 'flex', alignItems: 'center', width: '100%', gap: 8, padding: '6px 8px', background: 'transparent', border: 0, textAlign: 'left', cursor: 'pointer', borderRadius: 'var(--radius)' }}
              onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
              onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
            >
              <span>📄</span>
              <span style={{ flex: 1, fontSize: 12, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{doc.name}</span>
              {doc.category && <span style={{ fontSize: 10, color: 'var(--ink-3)' }}>{doc.category}</span>}
            </button>
          ))}
        </div>
      )}

      {pendingFiles && (
        <UploadModal
          files={pendingFiles}
          defaultMeta={{ propertyId, unitId, scope: unitId ? 'einheit' : 'allgemein', transactionId, category: 'Rechnung' }}
          onConfirm={() => { setPendingFiles(null); reload(); }}
          onCancel={() => setPendingFiles(null)}
        />
      )}
    </div>
  );
}

function initialTxForm(initial, defaultPropertyId, defaultUnitId, defaultType, today) {
  return {
    propertyId: initial?.propertyId ?? defaultPropertyId ?? '',
    unitId: initial?.unitId ?? defaultUnitId ?? '',
    date: initial?.date || today,
    type: initial?.type || defaultType || 'einnahme',
    amount: initial != null ? String(Math.abs(initial.amount || 0)) : '',
    category: initial?.category || '',
    description: initial?.description || '',
    notes: initial?.notes || '',
  };
}

const CONTACT_CATEGORIES = ['Handwerk', 'Service', 'Beratung', 'Versicherung', 'Verwaltung', 'Sonstiges'];

function ContactForm({ open, onClose, store, initial }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [form, setForm] = React.useState(() => initialContactForm(initial));
  React.useEffect(() => { if (open) { setForm(initialContactForm(initial)); setErr(null); } }, [open, initial]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const submit = async (e) => {
    e.preventDefault();
    if (!form.company.trim()) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        company: form.company.trim(),
        contactPerson: form.contactPerson.trim() || null,
        trade: form.trade.trim() || null,
        category: form.category || null,
        favorite: !!form.favorite,
        rating: form.rating ? Number(form.rating) : null,
        phone: form.phone.trim() || null,
        mobile: form.mobile.trim() || null,
        email: form.email.trim() || null,
        website: form.website.trim() || null,
        address: form.address.trim() || null,
        iban: form.iban.trim() || null,
        ustId: form.ustId.trim() || null,
        notes: form.notes.trim() || null,
      };
      if (initial?.id) await store.updateContact(initial.id, body);
      else await store.addContact(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal wide open={open} onClose={busy ? null : onClose} title={initial ? 'Kontakt bearbeiten' : 'Neuer Kontakt'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="contact-form" className="btn btn-primary" disabled={busy || !form.company.trim()}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="contact-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Firma / Name" required>
          <input className="form-input" value={form.company} onChange={e => update('company', e.target.value)} placeholder="z.B. Klempnerei Heinrich GmbH" autoFocus />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Ansprechpartner">
            <input className="form-input" value={form.contactPerson} onChange={e => update('contactPerson', e.target.value)} />
          </FormField>
          <FormField label="Gewerk">
            <input className="form-input" value={form.trade} onChange={e => update('trade', e.target.value)} placeholder="z.B. Klempner / Sanitär" />
          </FormField>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Kategorie">
            <select className="form-input" value={form.category || ''} onChange={e => update('category', e.target.value)}>
              <option value="">— wählen —</option>
              {CONTACT_CATEGORIES.map(c => <option key={c} value={c}>{c}</option>)}
            </select>
          </FormField>
          <FormField label="Bewertung (1-5)">
            <input type="number" min="1" max="5" className="form-input" value={form.rating} onChange={e => update('rating', e.target.value)} />
          </FormField>
        </div>
        <FormField label="">
          <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, cursor: 'pointer' }}>
            <input type="checkbox" checked={!!form.favorite} onChange={e => update('favorite', e.target.checked)} />
            ⭐ Als Favorit markieren
          </label>
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Telefon">
            <input type="tel" className="form-input" value={form.phone} onChange={e => update('phone', e.target.value)} />
          </FormField>
          <FormField label="Mobil">
            <input type="tel" className="form-input" value={form.mobile} onChange={e => update('mobile', e.target.value)} />
          </FormField>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="E-Mail">
            <input type="email" className="form-input" value={form.email} onChange={e => update('email', e.target.value)} />
          </FormField>
          <FormField label="Webseite">
            <input className="form-input" value={form.website} onChange={e => update('website', e.target.value)} placeholder="https://…" />
          </FormField>
        </div>
        <FormField label="Adresse">
          <input className="form-input" value={form.address} onChange={e => update('address', e.target.value)} />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="IBAN">
            <input className="form-input" value={form.iban} onChange={e => update('iban', e.target.value)} placeholder="DE…" />
          </FormField>
          <FormField label="USt-IdNr">
            <input className="form-input" value={form.ustId} onChange={e => update('ustId', e.target.value)} />
          </FormField>
        </div>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

function initialContactForm(initial) {
  return {
    company: initial?.company || '',
    contactPerson: initial?.contactPerson || '',
    trade: initial?.trade || '',
    category: initial?.category || '',
    favorite: !!initial?.favorite,
    rating: initial?.rating || '',
    phone: initial?.phone || '',
    mobile: initial?.mobile || '',
    email: initial?.email || '',
    website: initial?.website || '',
    address: initial?.address || '',
    iban: initial?.iban || '',
    ustId: initial?.ustId || '',
    notes: initial?.notes || '',
  };
}

const MAINT_STATUSES = [
  { value: 'geplant', label: 'Geplant' },
  { value: 'in-arbeit', label: 'In Arbeit' },
  { value: 'erledigt', label: 'Erledigt' },
];

function MaintenanceForm({ open, onClose, store, properties, contacts, initial, defaultPropertyId, defaultUnitId }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [form, setForm] = React.useState(() => initialMaintForm(initial, defaultPropertyId, defaultUnitId));
  React.useEffect(() => { if (open) { setForm(initialMaintForm(initial, defaultPropertyId, defaultUnitId)); setErr(null); } }, [open, initial, defaultPropertyId, defaultUnitId]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const propUnits = (properties || []).find(p => p.id === form.propertyId)?.units || [];

  const submit = async (e) => {
    e.preventDefault();
    if (!form.title.trim()) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        propertyId: form.propertyId || null,
        unitId: form.unitId || null,
        contactId: form.contactId || null,
        title: form.title.trim(),
        description: form.description.trim() || null,
        status: form.status || 'geplant',
        cost: form.cost ? Number(form.cost) : null,
        dueDate: form.dueDate || null,
        notes: form.notes.trim() || null,
      };
      if (initial?.id) await store.updateMaintenance(initial.id, body);
      else await store.addMaintenance(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Wartung bearbeiten' : 'Neue Wartung / Reparatur'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="maint-form" className="btn btn-primary" disabled={busy || !form.title.trim()}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="maint-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Titel" required>
          <input className="form-input" value={form.title} onChange={e => update('title', e.target.value)} placeholder="z.B. Heizung warten, Fassade streichen" autoFocus />
        </FormField>
        <FormField label="Beschreibung">
          <textarea className="form-input" rows={2} value={form.description} onChange={e => update('description', e.target.value)} placeholder="Details zur Arbeit, Mängel etc." />
        </FormField>
        <FormField label="Objekt">
          <select className="form-input" value={form.propertyId || ''} onChange={e => { update('propertyId', e.target.value); update('unitId', ''); }}>
            <option value="">— kein Objekt —</option>
            {(properties || []).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </FormField>
        {form.propertyId && propUnits.length > 0 && (
          <FormField label="Einheit (optional)">
            <select className="form-input" value={form.unitId || ''} onChange={e => update('unitId', e.target.value)}>
              <option value="">— Gesamtobjekt —</option>
              {propUnits.map(u => <option key={u.id} value={u.id}>{u.label}</option>)}
            </select>
          </FormField>
        )}
        <FormField label="Beauftragt an (Kontakt)">
          <select className="form-input" value={form.contactId || ''} onChange={e => update('contactId', e.target.value)}>
            <option value="">— noch kein Kontakt zugewiesen —</option>
            {(contacts || []).map(c => <option key={c.id} value={c.id}>{c.company}{c.trade ? ` (${c.trade})` : ''}</option>)}
          </select>
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Status">
            <select className="form-input" value={form.status} onChange={e => update('status', e.target.value)}>
              {MAINT_STATUSES.map(s => <option key={s.value} value={s.value}>{s.label}</option>)}
            </select>
          </FormField>
          <FormField label="Fällig am">
            <input type="date" className="form-input" value={form.dueDate} onChange={e => update('dueDate', e.target.value)} />
          </FormField>
        </div>
        <FormField label="Kosten (€) — Schätzung oder tatsächlich">
          <input type="number" className="form-input" value={form.cost} onChange={e => update('cost', e.target.value)} step="10" />
        </FormField>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

function initialMaintForm(initial, defaultPropertyId, defaultUnitId) {
  return {
    propertyId: initial?.propertyId ?? defaultPropertyId ?? '',
    unitId: initial?.unitId ?? defaultUnitId ?? '',
    contactId: initial?.contactId ?? '',
    title: initial?.title || '',
    description: initial?.description || '',
    status: initial?.status || 'geplant',
    cost: initial?.cost || '',
    dueDate: initial?.dueDate || '',
    notes: initial?.notes || '',
  };
}

const REMINDER_CATEGORIES = ['Wartung', 'Frist', 'Vertrag', 'Versicherung', 'Steuer', 'Miete', 'Sonstiges'];
const REMINDER_PRIORITIES = [
  { value: 'niedrig', label: 'Niedrig' },
  { value: 'mittel', label: 'Mittel' },
  { value: 'hoch', label: 'Hoch' },
];

function ReminderForm({ open, onClose, store, properties, initial }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const today = new Date().toISOString().slice(0, 10);
  const [form, setForm] = React.useState(() => initialReminderForm(initial, today));
  React.useEffect(() => { if (open) { setForm(initialReminderForm(initial, today)); setErr(null); } }, [open, initial]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const submit = async (e) => {
    e.preventDefault();
    if (!form.title.trim() || !form.date) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        date: form.date,
        title: form.title.trim(),
        category: form.category || null,
        priority: form.priority || 'mittel',
        propertyId: form.propertyId || null,
        notes: form.notes.trim() || null,
      };
      if (initial?.id) await store.updateReminder(initial.id, body);
      else await store.addReminder(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Termin bearbeiten' : 'Neuer Termin / Erinnerung'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="reminder-form" className="btn btn-primary" disabled={busy || !form.title.trim() || !form.date}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="reminder-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Titel" required>
          <input className="form-input" value={form.title} onChange={e => update('title', e.target.value)} placeholder="z.B. Heizungsablesung, Versicherung verlängern" autoFocus />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Datum" required>
            <input type="date" className="form-input" value={form.date} onChange={e => update('date', e.target.value)} />
          </FormField>
          <FormField label="Priorität">
            <select className="form-input" value={form.priority} onChange={e => update('priority', e.target.value)}>
              {REMINDER_PRIORITIES.map(p => <option key={p.value} value={p.value}>{p.label}</option>)}
            </select>
          </FormField>
        </div>
        <FormField label="Kategorie">
          <select className="form-input" value={form.category || ''} onChange={e => update('category', e.target.value)}>
            <option value="">— wählen —</option>
            {REMINDER_CATEGORIES.map(c => <option key={c} value={c}>{c}</option>)}
          </select>
        </FormField>
        <FormField label="Objekt (optional)">
          <select className="form-input" value={form.propertyId || ''} onChange={e => update('propertyId', e.target.value)}>
            <option value="">— kein bestimmtes Objekt —</option>
            {(properties || []).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </FormField>
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

function initialReminderForm(initial, today) {
  return {
    date: initial?.date || today,
    title: initial?.title || '',
    category: initial?.category || '',
    priority: initial?.priority || 'mittel',
    propertyId: initial?.propertyId ?? '',
    notes: initial?.notes || '',
  };
}

// ── Bank-CSV-Import-Modal ────────────────────────────────────────────
function CsvImportModal({ open, onClose, store, properties, defaultPropertyId, defaultUnitId }) {
  const [file, setFile] = React.useState(null);
  const [propertyId, setPropertyId] = React.useState(defaultPropertyId || '');
  const [unitId, setUnitId] = React.useState(defaultUnitId || '');
  const [autoCategorize, setAutoCategorize] = React.useState(true);
  const [stage, setStage] = React.useState('pick'); // pick | preview | result
  const [busy, setBusy] = React.useState(false);
  const [preview, setPreview] = React.useState(null);
  const [result, setResult] = React.useState(null);
  const [err, setErr] = React.useState(null);
  const inputRef = React.useRef(null);

  const [catProgress, setCatProgress] = React.useState(null); // {total, done, categorized, finished}

  const reset = () => { setFile(null); setStage('pick'); setPreview(null); setResult(null); setErr(null); setBusy(false); setCatProgress(null); };
  React.useEffect(() => { if (open) { reset(); setPropertyId(defaultPropertyId || ''); setUnitId(defaultUnitId || ''); setAutoCategorize(true); } }, [open, defaultPropertyId, defaultUnitId]);

  // Poll the categorize job while it's running
  React.useEffect(() => {
    if (!result?.categorizeJobId || catProgress?.finished) return;
    let cancelled = false;
    const tick = async () => {
      try {
        const s = await window.getCategorizeStatus(result.categorizeJobId);
        if (cancelled) return;
        setCatProgress(s);
        if (!s.finished) setTimeout(tick, 1500);
        else if (store?.reload) store.reload(); // load fresh categories into UI
      } catch (e) {
        if (!cancelled) { setCatProgress(p => ({ ...(p || {}), error: e.message, finished: true })); }
      }
    };
    tick();
    return () => { cancelled = true; };
  }, [result?.categorizeJobId, catProgress?.finished, store]);

  const propUnits = (properties || []).find(p => p.id === propertyId)?.units || [];

  const onPick = (files) => {
    const f = (files && files[0]) || null;
    if (f) setFile(f);
  };

  const runDryRun = async () => {
    if (!file) return;
    setBusy(true); setErr(null);
    try {
      const r = await window.importTransactionsCsv(file, { propertyId, unitId, dryRun: true });
      setPreview(r);
      setStage('preview');
    } catch (e) {
      setErr(e.detail || e.message);
    } finally {
      setBusy(false);
    }
  };

  const runImport = async () => {
    setBusy(true); setErr(null);
    try {
      const r = await window.importTransactionsCsv(file, { propertyId, unitId, dryRun: false, autoCategorize });
      setResult(r);
      setStage('result');
      // Refresh global data so dashboard / unit detail show new transactions
      if (store?.reload) await store.reload();
    } catch (e) {
      setErr(e.detail || e.message);
    } finally {
      setBusy(false);
    }
  };

  return (
    <Modal wide open={open} onClose={busy ? null : onClose} title="Bankdaten importieren (CSV)"
      footer={
        stage === 'pick' ? (
          <>
            <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
            <button type="button" className="btn btn-primary" disabled={!file || busy} onClick={runDryRun}>
              {busy ? 'Analysiere…' : 'Vorschau'}
            </button>
          </>
        ) : stage === 'preview' ? (
          <>
            <button type="button" className="btn btn-ghost" onClick={() => setStage('pick')} disabled={busy}>← Zurück</button>
            <button type="button" className="btn btn-primary" disabled={busy} onClick={runImport}>
              {busy ? `Importiert…` : `${preview?.total || 0} Zeilen importieren`}
            </button>
          </>
        ) : (
          <>
            <button type="button" className="btn btn-ghost" onClick={() => { setStage('pick'); setFile(null); }}>Weitere Datei</button>
            <button type="button" className="btn btn-primary" onClick={onClose}>Schließen</button>
          </>
        )
      }>
      {stage === 'pick' && (
        <div>
          <FormField label="CSV-Datei" required>
            <div
              onClick={() => inputRef.current?.click()}
              onDragOver={e => e.preventDefault()}
              onDrop={e => { e.preventDefault(); onPick(e.dataTransfer.files); }}
              style={{ padding: 24, border: '1.5px dashed var(--line-strong)', borderRadius: 'var(--radius)', background: file ? 'var(--accent-soft)' : 'var(--bg-sunken)', cursor: 'pointer', textAlign: 'center' }}
            >
              <div style={{ fontSize: 22, color: 'var(--accent)' }}>📊</div>
              <div style={{ fontSize: 13, fontWeight: 500, marginTop: 4 }}>
                {file ? file.name : 'CSV hierher ziehen oder klicken'}
              </div>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>
                {file ? `${(file.size / 1024).toFixed(1)} KB` : 'DKB · Sparkasse · ING · Comdirect · N26 · Volksbank'}
              </div>
              <input ref={inputRef} type="file" accept=".csv,.tsv,.txt" style={{ display: 'none' }} onChange={e => onPick(e.target.files)} />
            </div>
          </FormField>

          <FormField label="Buchungen zuordnen zu Objekt (optional)" hint="Leer lassen wenn das Konto verschiedene Objekte mischt — dann später manuell pro Buchung zuordnen">
            <select className="form-input" value={propertyId} onChange={e => { setPropertyId(e.target.value); setUnitId(''); }}>
              <option value="">— kein Objekt (wird leer importiert) —</option>
              {(properties || []).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
            </select>
          </FormField>
          {propertyId && propUnits.length > 0 && (
            <FormField label="Wohnung (optional)">
              <select className="form-input" value={unitId} onChange={e => setUnitId(e.target.value)}>
                <option value="">— Gesamtobjekt —</option>
                {propUnits.map(u => <option key={u.id} value={u.id}>{u.label}</option>)}
              </select>
            </FormField>
          )}

          <FormField label="">
            <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, cursor: 'pointer', padding: '8px 0' }}>
              <input type="checkbox" checked={autoCategorize} onChange={e => setAutoCategorize(e.target.checked)} />
              🤖 Buchungen automatisch kategorisieren (KI analysiert Empfänger + Verwendungszweck)
            </label>
          </FormField>

          <div style={{ marginTop: 12, padding: 12, background: 'var(--bg-sunken)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--ink-3)', lineHeight: 1.5 }}>
            <strong>Wie Duplikate erkannt werden:</strong> Jede Buchung wird per Hash aus Datum + Betrag + Empfänger + Verwendungszweck identifiziert. Doppelt importierte Buchungen werden ignoriert (nicht ersetzt).
          </div>
          {err && <div style={{ color: 'var(--neg)', fontSize: 12, marginTop: 12 }}>⚠ {err}</div>}
        </div>
      )}

      {stage === 'preview' && preview && (
        <div>
          <div style={{ marginBottom: 16, fontSize: 13 }}>
            <div><strong>{preview.total}</strong> Zeilen erkannt · Trennzeichen <code>{preview.detectedDelimiter}</code></div>
            <div style={{ color: 'var(--ink-3)', marginTop: 4, fontSize: 12 }}>
              Spalten erkannt: Datum, Betrag{preview.columnMapping?.counterparty !== -1 ? ', Empfänger' : ''}{preview.columnMapping?.description !== -1 ? ', Verwendungszweck' : ''}
              {preview.columnMapping?.iban !== -1 ? ', IBAN' : ''}
            </div>
            {preview.errors?.length > 0 && (
              <div style={{ color: 'var(--warn)', marginTop: 8, fontSize: 12 }}>
                ⚠ {preview.errors.length} Zeile(n) konnten nicht gelesen werden (Datum / Betrag fehlt)
              </div>
            )}
          </div>

          <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 6 }}>
            Vorschau (erste 5 Zeilen)
          </div>
          <div style={{ overflowX: 'auto', border: '1px solid var(--line)', borderRadius: 'var(--radius)' }}>
            <table className="table" style={{ fontSize: 12 }}>
              <thead><tr><th>Datum</th><th>Empfänger</th><th>Verwendungszweck</th><th className="num">Betrag</th></tr></thead>
              <tbody>
                {preview.preview?.map((p, i) => (
                  <tr key={i}>
                    <td>{p.date}</td>
                    <td>{p.counterparty || '—'}</td>
                    <td style={{ maxWidth: 280, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.description || '—'}</td>
                    <td className="num strong" style={{ color: p.amount >= 0 ? 'var(--pos)' : 'var(--neg)' }}>
                      {p.amount >= 0 ? '+' : ''}{p.amount.toFixed(2)} €
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>

          {err && <div style={{ color: 'var(--neg)', fontSize: 12, marginTop: 12 }}>⚠ {err}</div>}
        </div>
      )}

      {stage === 'result' && result && (
        <div style={{ padding: '20px 0' }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 16 }}>
            <div style={{ padding: 16, background: 'var(--accent-soft)', border: '1px solid var(--accent)', borderRadius: 'var(--radius)' }}>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Neu importiert</div>
              <div style={{ fontSize: 28, fontWeight: 500, color: 'var(--accent)' }}>{result.inserted}</div>
            </div>
            <div style={{ padding: 16, background: 'var(--bg-sunken)', border: '1px solid var(--line)', borderRadius: 'var(--radius)' }}>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Duplikate</div>
              <div style={{ fontSize: 28, fontWeight: 500, color: 'var(--ink-2)' }}>{result.duplicates}</div>
            </div>
            <div style={{ padding: 16, background: 'var(--bg-sunken)', border: '1px solid var(--line)', borderRadius: 'var(--radius)' }}>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Fehler</div>
              <div style={{ fontSize: 28, fontWeight: 500, color: result.errors?.length ? 'var(--neg)' : 'var(--ink-4)' }}>{result.errors?.length || 0}</div>
            </div>
          </div>

          {result.categorizeJobId && (
            <div style={{ padding: '14px 16px', background: catProgress?.finished ? 'var(--accent-soft)' : 'var(--bg-sunken)', border: `1px solid ${catProgress?.finished ? 'var(--accent)' : 'var(--line)'}`, borderRadius: 'var(--radius)', marginBottom: 16 }}>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
                <div style={{ fontSize: 13, fontWeight: 500 }}>
                  {catProgress?.finished
                    ? `🤖 ✓ Kategorisierung abgeschlossen — ${catProgress.categorized} von ${catProgress.total} kategorisiert`
                    : `🤖 KI kategorisiert Buchungen…`}
                </div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)', fontVariantNumeric: 'tabular-nums' }}>
                  {catProgress ? `${catProgress.done} / ${catProgress.total}` : `… / ${result.categorizeTotal}`}
                </div>
              </div>
              <div style={{ height: 6, background: 'var(--line-2)', borderRadius: 999, overflow: 'hidden' }}>
                <div style={{
                  height: '100%',
                  width: catProgress ? `${(catProgress.done / Math.max(1, catProgress.total)) * 100}%` : '5%',
                  background: 'var(--accent)',
                  transition: 'width 200ms',
                }} />
              </div>
              {!catProgress?.finished && (
                <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 6 }}>
                  Du kannst das Fenster schließen — die KI läuft im Hintergrund weiter, die Kategorien erscheinen automatisch im Dashboard.
                </div>
              )}
              {catProgress?.error && <div style={{ fontSize: 12, color: 'var(--neg)', marginTop: 6 }}>⚠ {catProgress.error}</div>}
            </div>
          )}

          <div style={{ fontSize: 13, color: 'var(--ink-2)', textAlign: 'center' }}>
            ✓ Import abgeschlossen. Buchungen findest du im jeweiligen Objekt unter Einnahmen / Ausgaben.
          </div>
          {result.errors?.length > 0 && (
            <details style={{ marginTop: 16, fontSize: 12, color: 'var(--ink-3)' }}>
              <summary>Fehlerdetails</summary>
              <ul style={{ marginTop: 8 }}>
                {result.errors.slice(0, 10).map((e, i) => <li key={i}>Zeile {e.row}: {e.reason} ({String(e.value).slice(0, 40)})</li>)}
              </ul>
            </details>
          )}
        </div>
      )}
    </Modal>
  );
}

// ── AssetForm: Anlagengut für AfA-Verzeichnis ──────────────────────
const ASSET_TYPES = [
  { value: 'gebäude',        label: 'Gebäude (Hauptanlage)',   defaultRate: 2.0 },
  { value: 'modernisierung', label: 'Modernisierung / Erhaltung', defaultRate: 10.0 },
  { value: 'inventar',       label: 'Inventar / GWG',           defaultRate: 33.33 },
];

function AssetForm({ open, onClose, store, properties, initial, defaultPropertyId }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const initF = (i) => ({
    propertyId: i?.propertyId || defaultPropertyId || '',
    type: i?.type || 'modernisierung',
    label: i?.label || '',
    acquisitionDate: i?.acquisitionDate || new Date().toISOString().slice(0, 10),
    acquisitionCost: i?.acquisitionCost || '',
    afaRate: i?.afaRate || 2.0,
    usefulLifeYears: i?.usefulLifeYears || '',
    notes: i?.notes || '',
  });
  const [form, setForm] = React.useState(() => initF(initial));
  React.useEffect(() => { if (open) { setForm(initF(initial)); setErr(null); } }, [open, initial, defaultPropertyId]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));

  // Auto-Suggestion für Gebäude-AfA: pre-1925 = 2.5, post-1925 = 2.0
  React.useEffect(() => {
    if (form.type === 'gebäude' && form.propertyId) {
      const prop = (properties || []).find(p => p.id === form.propertyId);
      if (prop?.yearBuilt) {
        const suggestedRate = prop.yearBuilt < 1925 ? 2.5 : 2.0;
        if (Math.abs(form.afaRate - suggestedRate) > 0.01) update('afaRate', suggestedRate);
      }
    }
  }, [form.type, form.propertyId]);

  const submit = async (e) => {
    e.preventDefault();
    if (!form.label.trim() || !form.acquisitionDate || !form.acquisitionCost) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        propertyId: form.propertyId || null,
        type: form.type,
        label: form.label.trim(),
        acquisitionDate: form.acquisitionDate,
        acquisitionCost: Number(form.acquisitionCost),
        afaRate: Number(form.afaRate),
        usefulLifeYears: form.usefulLifeYears ? Number(form.usefulLifeYears) : null,
        notes: form.notes.trim() || null,
      };
      if (initial?.id) await store.updateAsset(initial.id, body);
      else await store.addAsset(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  // Vorschau: jährliche AfA + Nutzungsdauer
  const yearlyAfa = form.afaRate > 0 && form.acquisitionCost ? Number(form.acquisitionCost) * (Number(form.afaRate) / 100) : 0;
  const yearsToFullDepreciation = form.afaRate > 0 ? Math.ceil(100 / Number(form.afaRate)) : 0;

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Anlagengut bearbeiten' : 'Neue Anlage / Modernisierung'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="asset-form" className="btn btn-primary" disabled={busy || !form.label.trim() || !form.acquisitionDate || !form.acquisitionCost}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="asset-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Objekt">
          <select className="form-input" value={form.propertyId} onChange={e => update('propertyId', e.target.value)}>
            <option value="">— kein Objekt —</option>
            {(properties || []).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </FormField>
        <FormField label="Typ" required>
          <select className="form-input" value={form.type} onChange={e => { update('type', e.target.value); const t = ASSET_TYPES.find(t => t.value === e.target.value); if (t) update('afaRate', t.defaultRate); }}>
            {ASSET_TYPES.map(t => <option key={t.value} value={t.value}>{t.label}</option>)}
          </select>
        </FormField>
        <FormField label="Bezeichnung" required>
          <input className="form-input" value={form.label} onChange={e => update('label', e.target.value)} placeholder={form.type === 'gebäude' ? 'z.B. Gebäudeanteil Lindenstraße 42' : form.type === 'modernisierung' ? 'z.B. Bad-Renovierung Wohnung 4' : 'z.B. Einbauküche Wohnung 1'} autoFocus />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Anschaffungsdatum" required>
            <input type="date" className="form-input" value={form.acquisitionDate} onChange={e => update('acquisitionDate', e.target.value)} />
          </FormField>
          <FormField label="Anschaffungskosten (€)" required>
            <input type="number" className="form-input" value={form.acquisitionCost} onChange={e => update('acquisitionCost', e.target.value)} step="0.01" placeholder="0,00" />
          </FormField>
        </div>
        <FormField label="AfA-Satz (%)" hint="Gebäude: 2,0 % (Baujahr ab 1925) bzw. 2,5 % (vor 1925) · Modernisierung über 4.000 €: meist 10 % über 10 J · Inventar: über die Nutzungsdauer">
          <input type="number" className="form-input" value={form.afaRate} onChange={e => update('afaRate', e.target.value)} step="0.1" min="0" max="100" />
        </FormField>
        {yearlyAfa > 0 && (
          <div style={{ padding: 12, background: 'var(--accent-soft)', border: '1px solid var(--accent)', borderRadius: 'var(--radius)', fontSize: 13 }}>
            <div style={{ fontWeight: 500, color: 'var(--accent)' }}>📐 AfA-Vorschau</div>
            <div style={{ marginTop: 4, color: 'var(--ink-2)' }}>
              <strong>{yearlyAfa.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })}</strong> jährlich,
              vollständig abgeschrieben nach <strong>{yearsToFullDepreciation} Jahren</strong>
            </div>
          </div>
        )}
        <FormField label="Notiz">
          <textarea className="form-input" rows={2} value={form.notes} onChange={e => update('notes', e.target.value)} />
        </FormField>
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

// ── TaskForm: einfache To-do mit Property/Unit-Bezug ──────────────
function TaskForm({ open, onClose, store, properties, initial }) {
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const initF = (i) => ({
    title: i?.title || '',
    description: i?.description || '',
    propertyId: i?.propertyId || '',
    unitId: i?.unitId || '',
    dueDate: i?.dueDate || '',
    priority: i?.priority || 'mittel',
  });
  const [form, setForm] = React.useState(() => initF(initial));
  React.useEffect(() => { if (open) { setForm(initF(initial)); setErr(null); } }, [open, initial]);

  const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const propUnits = (properties || []).find(p => p.id === form.propertyId)?.units || [];

  const submit = async (e) => {
    e.preventDefault();
    if (!form.title.trim()) return;
    setBusy(true); setErr(null);
    try {
      const body = {
        title: form.title.trim(),
        description: form.description.trim() || null,
        propertyId: form.propertyId || null,
        unitId: form.unitId || null,
        dueDate: form.dueDate || null,
        priority: form.priority,
      };
      if (initial?.id) await store.updateTask(initial.id, body);
      else await store.addTask(body);
      onClose();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  return (
    <Modal open={open} onClose={busy ? null : onClose} title={initial ? 'Aufgabe bearbeiten' : 'Neue Aufgabe'}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="submit" form="task-form" className="btn btn-primary" disabled={busy || !form.title.trim()}>
            {busy ? 'Speichert…' : (initial ? 'Speichern' : 'Anlegen')}
          </button>
        </>
      }>
      <form id="task-form" onSubmit={submit} onKeyDown={noEnterSubmit}>
        <FormField label="Titel" required>
          <input className="form-input" value={form.title} onChange={e => update('title', e.target.value)} placeholder="z.B. Mietvertrag verlängern" autoFocus />
        </FormField>
        <FormField label="Beschreibung">
          <textarea className="form-input" rows={2} value={form.description} onChange={e => update('description', e.target.value)} />
        </FormField>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <FormField label="Fälligkeit">
            <input type="date" className="form-input" value={form.dueDate} onChange={e => update('dueDate', e.target.value)} />
          </FormField>
          <FormField label="Priorität">
            <select className="form-input" value={form.priority} onChange={e => update('priority', e.target.value)}>
              <option value="niedrig">Niedrig</option>
              <option value="mittel">Mittel</option>
              <option value="hoch">Hoch</option>
            </select>
          </FormField>
        </div>
        <FormField label="Objekt">
          <select className="form-input" value={form.propertyId} onChange={e => { update('propertyId', e.target.value); update('unitId', ''); }}>
            <option value="">— kein Objekt —</option>
            {(properties || []).map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
          </select>
        </FormField>
        {form.propertyId && propUnits.length > 0 && (
          <FormField label="Wohnung">
            <select className="form-input" value={form.unitId} onChange={e => update('unitId', e.target.value)}>
              <option value="">— Gesamtobjekt —</option>
              {propUnits.map(u => <option key={u.id} value={u.id}>{u.label}</option>)}
            </select>
          </FormField>
        )}
        {err && <div style={{ color: 'var(--neg)', fontSize: 12, padding: '8px 0' }}>{err}</div>}
      </form>
    </Modal>
  );
}

// Generic confirm dialog
function ConfirmDialog({ open, onClose, onConfirm, title, message, confirmLabel = 'Löschen', danger = true }) {
  const [busy, setBusy] = React.useState(false);
  if (!open) return null;
  const submit = async () => {
    setBusy(true);
    try { await onConfirm(); onClose(); } catch (e) { alert(e.message); }
    finally { setBusy(false); }
  };
  return (
    <Modal open={open} onClose={busy ? null : onClose} title={title}
      footer={
        <>
          <button type="button" className="btn btn-ghost" onClick={onClose} disabled={busy}>Abbrechen</button>
          <button type="button" className={`btn ${danger ? 'btn-danger' : 'btn-primary'}`} onClick={submit} disabled={busy} style={danger ? { background: 'var(--neg)', color: '#fff', border: 0 } : null}>
            {busy ? 'Lädt…' : confirmLabel}
          </button>
        </>
      }>
      <div style={{ padding: '8px 0', fontSize: 14, color: 'var(--ink-2)' }}>{message}</div>
    </Modal>
  );
}

Object.assign(window, {
  Modal, FormField, ConfirmDialog,
  PropertyForm, UnitForm, TenantForm, TransactionForm,
  ContactForm, MaintenanceForm, ReminderForm, CsvImportModal,
  AssetForm, TaskForm, ASSET_TYPES,
  PROPERTY_TYPES, UNIT_STATUSES, TX_CATEGORIES_INCOME, TX_CATEGORIES_EXPENSE,
  CONTACT_CATEGORIES, MAINT_STATUSES, REMINDER_CATEGORIES, REMINDER_PRIORITIES,
});
