/* ============================================================
   BAN YARO — Ausgaben-Tracker
   Tabs: Übersicht | Einträge | Statistik
   ============================================================ */

window.Page_expenses = (() => {

  let _container = null;
  let _appState  = null;
  let _tab       = 'uebersicht';

  // Cache
  let _summary   = null;
  let _entries   = [];
  let _statsData  = null;

  const TABS = [
    { id: 'uebersicht',   label: 'Übersicht',    icon: 'house-line'    },
    { id: 'eintraege',    label: 'Ausgaben',      icon: 'currency-eur'  },
    { id: 'dauerauftraege', label: 'Daueraufträge', icon: 'arrows-clockwise' },
    { id: 'statistik',   label: 'Statistik',    icon: 'chart-bar'     },
  ];

  const KATEGORIEN = [
    { id: 'tierarzt',    label: 'Tierarzt',    icon: 'syringe',      color: '#ef4444' },
    { id: 'futter',      label: 'Futter',      icon: 'bowl-food',    color: '#f59e0b' },
    { id: 'zubehoer',    label: 'Zubehör',     icon: 'shopping-bag', color: '#8b5cf6' },
    { id: 'versicherung',label: 'Versicherung',icon: 'shield',       color: '#3b82f6' },
    { id: 'sitter',      label: 'Sitter',      icon: 'paw-print',    color: '#10b981' },
    { id: 'sonstiges',   label: 'Sonstiges',   icon: 'receipt',      color: '#6b7280' },
  ];

  function _kat(id) {
    return KATEGORIEN.find(k => k.id === id) || { id, label: id, icon: 'receipt', color: '#6b7280' };
  }

  // ----------------------------------------------------------
  // LIFECYCLE
  // ----------------------------------------------------------
  async function init(container, appState) {
    _container = container;
    _appState  = appState;
    _summary   = null;
    _entries   = [];
    _statsData  = null;
    _render();
  }

  async function refresh() {
    _summary  = null;
    _entries  = [];
    _statsData = null;
    await _renderTab();
  }

  // ----------------------------------------------------------
  // SHELL
  // ----------------------------------------------------------
  function _render() {
    _container.innerHTML = `
      <div class="by-tabs exp-tabs" id="exp-tabs">
        ${TABS.map(t => `
          <button class="by-tab${t.id === _tab ? ' active' : ''}" data-tab="${t.id}">
            ${UI.icon(t.icon)} ${t.label}
          </button>
        `).join('')}
      </div>
      <div id="exp-content"></div>
      <button class="exp-fab" id="exp-fab" title="Neue Ausgabe">
        ${UI.icon('plus')}
      </button>
    `;

    _container.querySelectorAll('#exp-tabs .by-tab').forEach(btn => {
      btn.addEventListener('click', () => {
        _tab = btn.dataset.tab;
        _container.querySelectorAll('#exp-tabs .by-tab').forEach(b =>
          b.classList.toggle('active', b.dataset.tab === _tab)
        );
        _renderTab();
      });
    });

    _container.querySelector('#exp-fab')
      ?.addEventListener('click', () => _showForm(null));

    _renderTab();
  }

  // ----------------------------------------------------------
  // TAB ROUTER
  // ----------------------------------------------------------
  async function _renderTab() {
    const el = _container.querySelector('#exp-content');
    if (!el) return;
    el.innerHTML = `<div class="exp-loading">${UI.skeleton(4)}</div>`;
    try {
      switch (_tab) {
        case 'uebersicht':     await _renderUebersicht(el);     break;
        case 'eintraege':      await _renderEintraege(el);      break;
        case 'dauerauftraege': await _renderDauerauftraege(el); break;
        case 'statistik':      await _renderStatistik(el);      break;
      }
    } catch (e) {
      el.innerHTML = `<div class="exp-error">Fehler beim Laden: ${e.message || 'Unbekannter Fehler'}</div>`;
    }
  }

  // ----------------------------------------------------------
  // TAB: ÜBERSICHT
  // ----------------------------------------------------------
  async function _renderUebersicht(el) {
    if (!_summary) {
      _summary = await API.get('/expenses/summary');
    }
    const s = _summary;

    // Vormonatsvergleich berechnen
    const letzteMonat = await _getLetzteMonateData();
    const trendHtml = _trendHtml(letzteMonat);

    const kacheln = KATEGORIEN.map(k => {
      const betrag = s.monat[k.id] || 0;
      return `
        <div class="exp-kachel">
          <div class="exp-kachel-icon" style="background:${k.color}20;color:${k.color}">
            ${UI.icon(k.icon)}
          </div>
          <div class="exp-kachel-betrag" style="color:var(--c-primary)">${_fmt(betrag)}</div>
          <div class="exp-kachel-label">${k.label}</div>
        </div>`;
    }).join('');

    const verlauf = letzteMonat.length > 1 ? _vergleichHtml(letzteMonat) : '';

    el.innerHTML = `
      <div class="exp-hero-card">
        <div class="exp-hero-label">Dieser Monat</div>
        <div class="exp-hero-betrag">${_fmt(s.gesamt_monat)}</div>
        <div class="exp-hero-meta">
          ${UI.icon('calendar')} Dieses Jahr: <strong>${_fmt(s.gesamt_jahr)}</strong>
          ${trendHtml}
        </div>
      </div>
      <div class="exp-kachel-grid">${kacheln}</div>
      ${verlauf}
      <div style="height:80px"></div>
    `;
  }

  async function _getLetzteMonateData() {
    if (!_entries.length) {
      _entries = await API.get('/expenses?limit=500');
    }
    const monatMap = {};
    _entries.forEach(e => {
      const m = e.datum.substring(0, 7);
      monatMap[m] = (monatMap[m] || 0) + e.betrag;
    });
    return Object.entries(monatMap)
      .sort((a, b) => b[0].localeCompare(a[0]))
      .slice(0, 6)
      .reverse();
  }

  function _trendHtml(data) {
    // Vergleich: aktueller Monat vs. Vormonat
    if (data.length < 2) return '';
    const aktuell = data[data.length - 1][1];
    const vormonat = data[data.length - 2][1];
    if (!vormonat) return '';
    const diff = aktuell - vormonat;
    const pct  = Math.round(Math.abs(diff / vormonat) * 100);
    if (pct === 0) return '';
    const pfeil = diff > 0
      ? `<span class="exp-trend exp-trend--up">${UI.icon('arrow-up')} +${pct}% ggü. Vormonat</span>`
      : `<span class="exp-trend exp-trend--down">${UI.icon('arrow-down')} −${pct}% ggü. Vormonat</span>`;
    return pfeil;
  }

  function _vergleichHtml(data) {
    if (!data.length) return '';
    const max = Math.max(...data.map(d => d[1]), 1);
    const balken = data.map(([monat, summe]) => {
      const pct = Math.round((summe / max) * 100);
      const [y, m] = monat.split('-');
      const label = new Date(parseInt(y), parseInt(m) - 1, 1)
        .toLocaleString('de-DE', { month: 'short' });
      return `
        <div class="exp-bar-item">
          <div class="exp-bar-track">
            <div class="exp-bar-fill" style="height:${pct}%"></div>
          </div>
          <div class="exp-bar-label">${label}</div>
          <div class="exp-bar-val">${_fmtShort(summe)}</div>
        </div>`;
    }).join('');

    return `
      <div class="exp-section">
        <div class="exp-section-title">${UI.icon('chart-bar')} Verlauf (6 Monate)</div>
        <div class="exp-bar-chart">${balken}</div>
      </div>`;
  }

  // ----------------------------------------------------------
  // TAB: EINTRÄGE
  // ----------------------------------------------------------
  async function _renderEintraege(el) {
    if (!_entries.length) {
      _entries = await API.get('/expenses?limit=500');
    }

    if (!_entries.length) {
      el.innerHTML = UI.emptyState({
        icon:   UI.icon('receipt'),
        title:  'Noch keine Ausgaben',
        text:   'Tippe auf + um deine erste Ausgabe einzutragen.',
      });
      return;
    }

    // Nach Monat gruppieren
    const groups = {};
    _entries.forEach(e => {
      const m = e.datum.substring(0, 7);
      if (!groups[m]) groups[m] = [];
      groups[m].push(e);
    });

    const html = Object.entries(groups)
      .sort((a, b) => b[0].localeCompare(a[0]))
      .map(([monat, items]) => {
        const [y, m] = monat.split('-');
        const titel = new Date(parseInt(y), parseInt(m) - 1, 1)
          .toLocaleString('de-DE', { month: 'long', year: 'numeric' });
        const summe = items.reduce((s, e) => s + e.betrag, 0);

        const rows = items.map(e => {
          const k = _kat(e.kategorie);
          const datum = new Date(e.datum + 'T00:00:00')
            .toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit' });
          const dogBadge = e.dog_name
            ? `<span class="exp-dog-badge">${UI.icon('paw-print')} ${_esc(e.dog_name)}</span>`
            : '';
          const notiz = e.notiz
            ? `<span class="exp-entry-notiz">${_esc(e.notiz)}</span>`
            : '';
          return `
            <div class="exp-entry" data-id="${e.id}">
              <div class="exp-entry-icon-badge" style="--kat-color:${k.color}">
                ${UI.icon(k.icon)}
              </div>
              <div class="exp-entry-body">
                <div class="exp-entry-head">
                  <span class="exp-entry-datum">${datum}</span>
                  <span class="exp-entry-kat">${k.label}</span>
                  ${dogBadge}
                </div>
                ${notiz}
              </div>
              <div class="exp-entry-right">
                <div class="exp-entry-betrag">${_fmt(e.betrag)}</div>
                <button class="exp-entry-del" data-del="${e.id}" title="Löschen"
                        aria-label="Eintrag löschen">
                  ${UI.icon('trash')}
                </button>
              </div>
            </div>`;
        }).join('');

        return `
          <div class="exp-month-group">
            <div class="exp-month-header">
              <span class="exp-month-title">${titel}</span>
              <span class="exp-month-summe">${_fmt(summe)}</span>
            </div>
            ${rows}
          </div>`;
      }).join('');

    el.innerHTML = `<div class="exp-list">${html}</div><div style="height:80px"></div>`;

    // Klick auf Zeile → Bearbeiten (nur wenn nicht Löschen-Button)
    el.querySelectorAll('.exp-entry').forEach(row => {
      row.addEventListener('click', (ev) => {
        if (ev.target.closest('.exp-entry-del')) return;
        const id = parseInt(row.dataset.id);
        const entry = _entries.find(e => e.id === id);
        if (entry) _showForm(entry);
      });
    });

    // Löschen-Buttons
    el.querySelectorAll('.exp-entry-del').forEach(btn => {
      btn.addEventListener('click', async (ev) => {
        ev.stopPropagation();
        const id = parseInt(btn.dataset.del);
        if (!window.confirm('Diesen Eintrag wirklich löschen?')) return;
        try {
          await API.del(`/expenses/${id}`);
          UI.toast.success('Ausgabe gelöscht.');
          _invalidateCache();
          await _renderTab();
        } catch (e) {
          UI.toast.error(e.message || 'Fehler beim Löschen.');
        }
      });
    });
  }

  // ----------------------------------------------------------
  // TAB: DAUERAUFTRÄGE
  // ----------------------------------------------------------
  const HAEUFIGKEIT_LABEL = {
    monatlich:      'Monatlich',
    quartalsweise:  'Quartalsweise',
    jaehrlich:      'Jährlich',
  };

  async function _renderDauerauftraege(el) {
    let recurring = [];
    try { recurring = await API.get('/expenses/recurring'); } catch { /* leer */ }

    const cards = recurring.map(r => {
      const k = _kat(r.kategorie);
      const naechste = r.naechste_faelligkeit
        ? new Date(r.naechste_faelligkeit + 'T00:00:00')
            .toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })
        : '—';
      return `
        <div class="exp-recurring-card${r.aktiv ? '' : ' exp-recurring-card--inaktiv'}" data-rid="${r.id}">
          <div class="exp-entry-icon-badge" style="--kat-color:${k.color}">${UI.icon(k.icon)}</div>
          <div class="exp-entry-body">
            <div class="exp-entry-head">
              <span class="exp-entry-kat">${k.label}</span>
              <span class="exp-recurring-freq">${HAEUFIGKEIT_LABEL[r.haeufigkeit] || r.haeufigkeit}</span>
              ${r.dog_name ? `<span class="exp-dog-badge">${UI.icon('paw-print')} ${_esc(r.dog_name)}</span>` : ''}
            </div>
            ${r.notiz ? `<div class="exp-entry-notiz">${_esc(r.notiz)}</div>` : ''}
            <div class="exp-recurring-next">
              ${UI.icon('calendar')} Nächste Buchung: <strong>${naechste}</strong>
              ${!r.aktiv ? '<span class="exp-badge-inaktiv">Pausiert</span>' : ''}
            </div>
          </div>
          <div class="exp-entry-right">
            <div class="exp-entry-betrag">${_fmt(r.betrag)}</div>
            <div style="display:flex;gap:var(--space-1);margin-top:var(--space-1)">
              <button class="exp-icon-btn exp-recurring-toggle" data-rid="${r.id}" data-aktiv="${r.aktiv}"
                      title="${r.aktiv ? 'Pausieren' : 'Aktivieren'}">
                ${UI.icon(r.aktiv ? 'pause' : 'play')}
              </button>
              <button class="exp-icon-btn exp-icon-btn--danger exp-recurring-del" data-rid="${r.id}"
                      title="Löschen">${UI.icon('trash')}</button>
            </div>
          </div>
        </div>`;
    }).join('');

    el.innerHTML = `
      <div style="display:flex;justify-content:flex-end;margin-bottom:var(--space-3)">
        <button class="btn btn-primary btn-sm" id="exp-recurring-add">
          ${UI.icon('plus')} Dauerauftrag
        </button>
      </div>
      ${recurring.length
        ? `<div class="exp-list">${cards}</div>`
        : UI.emptyState({ icon: UI.icon('arrows-clockwise'),
            title: 'Keine Daueraufträge',
            text: 'Erfasse regelmäßige Ausgaben wie Hundesteuer oder Versicherung.' })}
      <div style="height:80px"></div>`;

    el.querySelector('#exp-recurring-add')?.addEventListener('click', () => _showRecurringForm(null, () => {
      _tab = 'dauerauftraege'; _renderTab();
    }));

    el.querySelectorAll('.exp-recurring-toggle').forEach(btn => {
      btn.addEventListener('click', async () => {
        const rid   = parseInt(btn.dataset.rid);
        const aktiv = btn.dataset.aktiv === '1';
        await UI.asyncButton(btn, async () => {
          await API.patch(`/expenses/recurring/${rid}`, { aktiv: !aktiv });
          _renderTab();
        });
      });
    });

    el.querySelectorAll('.exp-recurring-del').forEach(btn => {
      btn.addEventListener('click', async () => {
        if (!window.confirm('Dauerauftrag löschen?')) return;
        await UI.asyncButton(btn, async () => {
          await API.del(`/expenses/recurring/${btn.dataset.rid}`);
          _renderTab();
        });
      });
    });
  }

  function _showRecurringForm(r, onSave) {
    const today = new Date().toISOString().slice(0, 10);
    const katOptions = [
      { id: 'tierarzt', label: 'Tierarzt' }, { id: 'futter', label: 'Futter' },
      { id: 'zubehoer', label: 'Zubehör' }, { id: 'versicherung', label: 'Versicherung' },
      { id: 'sitter', label: 'Sitter' }, { id: 'sonstiges', label: 'Sonstiges' },
    ].map(k => `<option value="${k.id}" ${r?.kategorie === k.id ? 'selected' : ''}>${k.label}</option>`).join('');

    const dogOptions = (_appState.dogs || []).map(d =>
      `<option value="${d.id}" ${r?.dog_id === d.id ? 'selected' : ''}>${_esc(d.name)}</option>`
    ).join('');

    const body = `
      <form id="exp-recurring-form">
        <div class="form-group">
          <label class="form-label">Kategorie</label>
          <select class="form-control" name="kategorie">${katOptions}</select>
        </div>
        <div class="form-group">
          <label class="form-label">Betrag (€)</label>
          <input class="form-control" type="number" name="betrag" step="0.01" min="0.01"
                 value="${r?.betrag || ''}" placeholder="0,00" required>
        </div>
        <div class="form-group">
          <label class="form-label">Häufigkeit</label>
          <select class="form-control" name="haeufigkeit">
            <option value="monatlich"     ${r?.haeufigkeit === 'monatlich'     ? 'selected' : ''}>Monatlich</option>
            <option value="quartalsweise" ${r?.haeufigkeit === 'quartalsweise' ? 'selected' : ''}>Quartalsweise (alle 3 Monate)</option>
            <option value="jaehrlich"     ${r?.haeufigkeit === 'jaehrlich'     ? 'selected' : ''}>Jährlich</option>
          </select>
        </div>
        <div class="form-group">
          <label class="form-label">Startdatum</label>
          <input class="form-control" type="date" name="startdatum"
                 value="${r?.startdatum || today}" required>
        </div>
        ${dogOptions ? `
        <div class="form-group">
          <label class="form-label">Hund <span style="color:var(--c-text-muted)">(optional)</span></label>
          <select class="form-control" name="dog_id">
            <option value="">Kein Hund</option>${dogOptions}
          </select>
        </div>` : ''}
        <div class="form-group">
          <label class="form-label">Bezeichnung <span style="color:var(--c-text-muted)">(optional)</span></label>
          <input class="form-control" type="text" name="notiz"
                 value="${_esc(r?.notiz || '')}" placeholder="z.B. Haftpflicht Allianz">
        </div>
      </form>`;

    const footer = `
      <button type="button" class="btn btn-secondary flex-1" onclick="UI.modal.close()">Abbrechen</button>
      <button type="submit" form="exp-recurring-form" class="btn btn-primary flex-1">Speichern</button>`;

    UI.modal.open({ title: r ? 'Dauerauftrag bearbeiten' : 'Neuer Dauerauftrag', body, footer });

    document.getElementById('exp-recurring-form')?.addEventListener('submit', async e => {
      e.preventDefault();
      const btn = document.querySelector('[form="exp-recurring-form"][type="submit"]');
      const fd  = UI.formData(e.target);
      const payload = {
        kategorie:   fd.kategorie,
        betrag:      parseFloat(fd.betrag),
        haeufigkeit: fd.haeufigkeit,
        startdatum:  fd.startdatum,
        notiz:       fd.notiz || null,
        dog_id:      fd.dog_id ? parseInt(fd.dog_id) : null,
      };
      await UI.asyncButton(btn, async () => {
        if (r) {
          await API.patch(`/expenses/recurring/${r.id}`, payload);
        } else {
          await API.post('/expenses/recurring', payload);
        }
        UI.modal.close();
        onSave?.();
      });
    });
  }

  // ----------------------------------------------------------
  // TAB: STATISTIK
  // ----------------------------------------------------------
  async function _renderStatistik(el) {
    if (!_summary) {
      _summary = await API.get('/expenses/summary');
    }
    if (!_entries.length) {
      _entries = await API.get('/expenses?limit=500');
    }

    const s = _summary;
    const gesamtJahr = s.gesamt_jahr || 1;

    // Jahres-Aufteilung nach Kategorien (als Balken-Reihen)
    const katBalken = KATEGORIEN
      .filter(k => (s.jahr[k.id] || 0) > 0)
      .sort((a, b) => (s.jahr[b.id] || 0) - (s.jahr[a.id] || 0))
      .map(k => {
        const val = s.jahr[k.id] || 0;
        const pct = Math.round((val / gesamtJahr) * 100);
        return `
          <div class="exp-stat-row">
            <div class="exp-stat-label">
              <span class="exp-stat-icon" style="color:${k.color}">${UI.icon(k.icon)}</span>
              ${k.label}
            </div>
            <div class="exp-stat-bar-wrap">
              <div class="exp-stat-bar" style="width:${pct}%;background:${k.color}"></div>
            </div>
            <div class="exp-stat-pct">${pct}%</div>
            <div class="exp-stat-val">${_fmt(val)}</div>
          </div>`;
      }).join('');

    // Monats-Balken mit gestapelten Top-2-Kategorien
    const heute = new Date();
    const jahrStr = heute.getFullYear().toString();

    // Pro Monat: Summe je Kategorie berechnen
    const monatKatMap = {}; // { monat: { katId: summe } }
    _entries
      .filter(e => e.datum.startsWith(jahrStr))
      .forEach(e => {
        const m = parseInt(e.datum.split('-')[1]);
        if (!monatKatMap[m]) monatKatMap[m] = {};
        monatKatMap[m][e.kategorie] = (monatKatMap[m][e.kategorie] || 0) + e.betrag;
      });

    const monatTotalMap = {};
    Object.entries(monatKatMap).forEach(([m, katObj]) => {
      monatTotalMap[m] = Object.values(katObj).reduce((a, b) => a + b, 0);
    });

    const maxMonat = Math.max(...Object.values(monatTotalMap), 1);
    const MONATE = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'];

    const monatsBalken = MONATE.map((label, i) => {
      const mi = i + 1;
      const total = monatTotalMap[mi] || 0;
      const pct   = Math.round((total / maxMonat) * 100);
      const isAktiv = mi === (heute.getMonth() + 1);

      // Top-2-Kategorien für gestapelten Balken
      let stackHtml = '';
      if (total > 0 && monatKatMap[mi]) {
        const sorted = Object.entries(monatKatMap[mi])
          .sort((a, b) => b[1] - a[1])
          .slice(0, 2);
        // Gesamthöhe = pct%, verteile anteilig auf Top-2
        let rest = pct;
        const segments = sorted.map(([katId, val], idx) => {
          const k = _kat(katId);
          const segPct = idx < sorted.length - 1
            ? Math.round((val / total) * pct)
            : rest;
          rest -= segPct;
          return `<div class="exp-stack-seg" style="height:${segPct}%;background:${k.color}" title="${k.label}: ${_fmt(val)}"></div>`;
        });
        stackHtml = segments.join('');
      } else {
        stackHtml = `<div class="exp-stack-seg" style="height:${pct}%;background:var(--c-border)"></div>`;
      }

      return `
        <div class="exp-bar-item${isAktiv ? ' exp-bar-item--aktiv' : ''}">
          <div class="exp-bar-track exp-bar-track--stack">
            ${stackHtml}
          </div>
          <div class="exp-bar-label">${label}</div>
        </div>`;
    }).join('');

    // Donut-Übersicht (CSS-gradient)
    const donutHtml = _donutHtml(s, gesamtJahr);

    el.innerHTML = `
      <div class="exp-hero-card exp-hero-card--sm">
        <div class="exp-hero-label">Gesamt dieses Jahr</div>
        <div class="exp-hero-betrag">${_fmt(s.gesamt_jahr)}</div>
      </div>

      <div class="exp-section">
        <div class="exp-section-title">${UI.icon('chart-bar')} Monatsübersicht ${jahrStr}</div>
        <div class="exp-bar-chart exp-bar-chart--12">${monatsBalken}</div>
      </div>

      ${donutHtml}

      <div class="exp-section">
        <div class="exp-section-title">${UI.icon('chart-pie')} Aufteilung nach Kategorie</div>
        <div class="exp-stat-rows">
          ${katBalken || `<div class="exp-empty-hint">Noch keine Ausgaben dieses Jahr.</div>`}
        </div>
      </div>
      <div style="height:80px"></div>
    `;
  }

  // Donut via CSS conic-gradient
  function _donutHtml(s, gesamt) {
    const aktiveKat = KATEGORIEN.filter(k => (s.jahr[k.id] || 0) > 0);
    if (!aktiveKat.length) return '';

    // Stops für conic-gradient berechnen
    let offset = 0;
    const stops = [];
    aktiveKat.forEach(k => {
      const pct = (s.jahr[k.id] || 0) / gesamt * 100;
      stops.push(`${k.color} ${offset.toFixed(1)}% ${(offset + pct).toFixed(1)}%`);
      offset += pct;
    });
    const gradient = `conic-gradient(${stops.join(', ')})`;

    const legendeItems = aktiveKat
      .sort((a, b) => (s.jahr[b.id] || 0) - (s.jahr[a.id] || 0))
      .map(k => {
        const pct = Math.round((s.jahr[k.id] || 0) / gesamt * 100);
        return `
          <div class="exp-donut-legend-item">
            <span class="exp-donut-dot" style="background:${k.color}"></span>
            <span class="exp-donut-legend-label">${k.label}</span>
            <span class="exp-donut-legend-pct">${pct}%</span>
          </div>`;
      }).join('');

    return `
      <div class="exp-section">
        <div class="exp-section-title">${UI.icon('chart-pie')} Kategorien-Verteilung</div>
        <div class="exp-donut-wrap">
          <div class="exp-donut" style="background:${gradient}">
            <div class="exp-donut-hole"></div>
          </div>
          <div class="exp-donut-legend">${legendeItems}</div>
        </div>
      </div>`;
  }

  // ----------------------------------------------------------
  // FORMULAR — Neu / Bearbeiten
  // ----------------------------------------------------------
  function _showForm(entry) {
    const isEdit  = !!entry;
    const today   = new Date().toISOString().split('T')[0];
    const formId  = 'exp-form';
    const selKat  = entry?.kategorie || 'sonstiges';

    const dogOptions = (_appState.dogs || []).map(d =>
      `<option value="${d.id}"${entry?.dog_id === d.id ? ' selected' : ''}>${_esc(d.name)}</option>`
    ).join('');

    // Kategorie-Kacheln statt Dropdown
    const katKacheln = KATEGORIEN.map(k => `
      <label class="exp-kat-tile${selKat === k.id ? ' exp-kat-tile--sel' : ''}" data-kat="${k.id}">
        <input type="radio" name="kategorie" value="${k.id}" ${selKat === k.id ? 'checked' : ''} style="display:none">
        <span class="exp-kat-tile-icon" style="color:${k.color}">${UI.icon(k.icon)}</span>
        <span class="exp-kat-tile-label">${k.label}</span>
      </label>`).join('');

    const body = `
      <form id="${formId}" autocomplete="off">

        <div class="form-group">
          <label class="form-label">Kategorie</label>
          <div class="exp-kat-grid">${katKacheln}</div>
        </div>

        <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3)">
          <div class="form-group" style="margin-bottom:0">
            <label class="form-label">Betrag</label>
            <div class="exp-betrag-wrap">
              <span class="exp-betrag-prefix">€</span>
              <input type="number" name="betrag" class="form-control exp-betrag-input"
                     value="${entry?.betrag || ''}" min="0.01" step="0.01"
                     placeholder="0,00" required>
            </div>
          </div>
          <div class="form-group" style="margin-bottom:0">
            <label class="form-label">Datum</label>
            <input type="date" name="datum" class="form-control"
                   value="${entry?.datum || today}" required>
          </div>
        </div>

        ${dogOptions ? `
        <div class="form-group">
          <label class="form-label">Hund <span class="form-label-hint">(optional)</span></label>
          <select name="dog_id" class="form-control">
            <option value="">— kein Hund —</option>${dogOptions}
          </select>
        </div>` : ''}

        <div class="form-group">
          <label class="form-label">Notiz <span class="form-label-hint">(optional)</span></label>
          <input type="text" name="notiz" class="form-control"
                 value="${_esc(entry?.notiz || '')}"
                 placeholder="z.B. Hundesteuer 2026, Allianz Haftpflicht …">
        </div>

        ${!isEdit ? `
        <div class="exp-repeat-section">
          <label class="exp-repeat-toggle">
            <input type="checkbox" id="exp-wiederholen" name="wiederholen">
            <span class="exp-repeat-toggle-box"></span>
            <span>${UI.icon('arrows-clockwise')} Automatisch wiederholen</span>
          </label>
          <div id="exp-repeat-opts" style="display:none;margin-top:var(--space-3)">
            <select name="haeufigkeit" class="form-control">
              <option value="monatlich">Monatlich</option>
              <option value="quartalsweise">Quartalsweise (alle 3 Monate)</option>
              <option value="jaehrlich" selected>Jährlich</option>
            </select>
            <p style="font-size:var(--text-xs);color:var(--c-text-muted);margin:var(--space-2) 0 0">
              Der Betrag wird automatisch zum Fälligkeitstermin eingetragen.
            </p>
          </div>
        </div>` : ''}

      </form>`;

    const footer = isEdit ? `
      <button type="button" class="btn btn-ghost btn-sm" id="exp-delete-btn"
              style="color:var(--c-danger);margin-right:auto">
        ${UI.icon('trash')}
      </button>
      <button type="button" class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
      <button type="submit" form="${formId}" class="btn btn-primary">Speichern</button>
    ` : `
      <button type="button" class="btn btn-secondary flex-1" onclick="UI.modal.close()">Abbrechen</button>
      <button type="submit" form="${formId}" class="btn btn-primary flex-1">Speichern</button>
    `;

    const modal = UI.modal.open({ title: isEdit ? 'Ausgabe bearbeiten' : 'Neue Ausgabe', body, footer });

    // Kategorie-Kacheln interaktiv
    modal.querySelectorAll('.exp-kat-tile').forEach(tile => {
      tile.addEventListener('click', () => {
        modal.querySelectorAll('.exp-kat-tile').forEach(t => t.classList.remove('exp-kat-tile--sel'));
        tile.classList.add('exp-kat-tile--sel');
      });
    });

    // Wiederholen-Toggle
    modal.querySelector('#exp-wiederholen')?.addEventListener('change', e => {
      modal.querySelector('#exp-repeat-opts').style.display = e.target.checked ? 'block' : 'none';
    });

    if (isEdit) {
      modal.querySelector('#exp-delete-btn')?.addEventListener('click', async () => {
        if (!window.confirm('Diesen Eintrag wirklich löschen?')) return;
        try {
          await API.del(`/expenses/${entry.id}`);
          UI.modal.close();
          UI.toast.success('Ausgabe gelöscht.');
          _invalidateCache();
          await _renderTab();
        } catch (e) {
          UI.toast.error(e.message || 'Fehler beim Löschen.');
        }
      });
    }

    modal.querySelector(`#${formId}`)?.addEventListener('submit', async (ev) => {
      ev.preventDefault();
      const fd      = UI.formData(ev.target);
      const payload = {
        kategorie: fd.kategorie,
        betrag:    parseFloat(fd.betrag),
        datum:     fd.datum,
        notiz:     fd.notiz || null,
        dog_id:    fd.dog_id ? parseInt(fd.dog_id) : null,
      };

      try {
        if (isEdit) {
          await API.patch(`/expenses/${entry.id}`, payload);
          UI.toast.success('Ausgabe aktualisiert.');
        } else {
          await API.post('/expenses', payload);
          // Auch als Dauerauftrag anlegen wenn gewünscht
          if (fd.wiederholen) {
            await API.post('/expenses/recurring', {
              ...payload,
              haeufigkeit: fd.haeufigkeit || 'jaehrlich',
              startdatum:  fd.datum,
            });
            UI.toast.success('Ausgabe + Dauerauftrag gespeichert.');
          } else {
            UI.toast.success('Ausgabe gespeichert.');
          }
        }
        UI.modal.close();
        _invalidateCache();
        await _renderTab();
      } catch (e) {
        UI.toast.error(e.message || 'Fehler beim Speichern.');
      }
    });
  }

  // ----------------------------------------------------------
  // Hilfsfunktionen
  // ----------------------------------------------------------
  function _invalidateCache() {
    _summary  = null;
    _entries  = [];
    _statsData = null;
  }

  function _fmt(val) {
    return (val || 0).toLocaleString('de-DE', { style: 'currency', currency: 'EUR' });
  }

  function _fmtShort(val) {
    if (!val) return '0 €';
    if (val >= 1000) return (val / 1000).toFixed(1).replace('.', ',') + ' k€';
    return Math.round(val) + ' €';
  }

  function _esc(s) {
    if (!s) return '';
    return String(s)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
  }

  return { init, refresh };
})();
