// Finance data + chart components (ported & retuned for desktop)
const NUMS = { fontVariantNumeric: 'tabular-nums', fontFeatureSettings: '"tnum"' };

const finPalette = (t) => ({
  pos: t.green, neg: t.red,
  posBar: t.dark ? 'rgba(48,209,88,0.45)' : 'rgba(52,199,89,0.42)',
  negBar: t.dark ? 'rgba(255,69,58,0.42)' : 'rgba(255,59,48,0.36)',
  grid: t.dark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.07)',
});

// Monthly income/expense for the year (Mai 2026 = current)
const FIN_BARS = [
  { key: '2025-11', label: 'Nov', inc: 1640, exp: 720 },
  { key: '2025-12', label: 'Dez', inc: 980,  exp: 540 },
  { key: '2026-01', label: 'Jan', inc: 1320, exp: 880 },
  { key: '2026-02', label: 'Feb', inc: 1180, exp: 410 },
  { key: '2026-03', label: 'Mär', inc: 2040, exp: 1260 },
  { key: '2026-04', label: 'Apr', inc: 2260, exp: 690 },
  { key: '2026-05', label: 'Mai', inc: 2480, exp: 760 },
];

const SEED_TX = [
  { id: 't1', kind: 'in',  label: 'Hochzeit Müller',        sub: 'JBL EON 712 · 4 Tage',     amount: 180, date: '18. Mai 2026', dateISO: '2026-05-18' },
  { id: 't2', kind: 'in',  label: 'Gartenfest Bauer',       sub: 'Shure SM58 ×4 · 2 Tage',   amount: 60,  date: '19. Mai 2026', dateISO: '2026-05-19' },
  { id: 't3', kind: 'out', label: 'Ersatz-Speakon Kabel',   sub: 'Zubehör Tontechnik',       amount: 48,  date: '16. Mai 2026', dateISO: '2026-05-16' },
  { id: 't4', kind: 'in',  label: 'Vereinsfest TSV',        sub: 'Shure SM58 ×4 · 2 Tage',   amount: 60,  date: '27. Apr 2026', dateISO: '2026-04-27' },
  { id: 't5', kind: 'in',  label: 'Umzug Schmidt',          sub: 'Anhänger 750kg · 1 Tag',   amount: 40,  date: '15. Mai 2026', dateISO: '2026-05-15' },
  { id: 't6', kind: 'out', label: 'TÜV Anhänger 750kg',     sub: 'Werkstatt · HU/AU',        amount: 124, date: '12. Mai 2026', dateISO: '2026-05-12' },
  { id: 't7', kind: 'in',  label: 'Anzahlung Klein',        sub: 'PA-Komplettset · Reservierung', amount: 80, date: '10. Mai 2026', dateISO: '2026-05-10' },
  { id: 't8', kind: 'out', label: 'Versicherung Q2',        sub: 'Geräte-Inhaltsversicherung', amount: 95,  date: '04. Mai 2026', dateISO: '2026-05-04' },
];

// Per-month historical detail (used in the Monatsverlauf drill-down)
const CURRENT_MONTH_KEY = '2026-05';
const MONTHS_DETAIL = {
  '2026-01': { label: 'Januar 2026', short: 'Jan', income: 980, expenses: 320,
    bars: [{ label: 'W1', inc: 220, exp: 80 }, { label: 'W2', inc: 320, exp: 120 }, { label: 'W3', inc: 180, exp: 0 }, { label: 'W4', inc: 260, exp: 120 }],
    transactions: [
      { id: 'jan1', kind: 'in',  label: 'Silvesterparty',     sub: 'PA-Anlage · 2 Tage', amount: 420, date: '02.01.' },
      { id: 'jan2', kind: 'out', label: 'Anhänger Wartung',   sub: 'TÜV + Reparatur',    amount: 380, date: '14.01.' },
      { id: 'jan3', kind: 'in',  label: 'Firmenfeier Bauer',  sub: 'Mikro-Set · 1 Tag',  amount: 95,  date: '17.01.' },
      { id: 'jan4', kind: 'in',  label: 'Geburtstag Klein',   sub: 'JBL · 2 Tage',       amount: 90,  date: '24.01.' },
    ],
  },
  '2026-02': { label: 'Februar 2026', short: 'Feb', income: 1120, expenses: 480,
    bars: [{ label: 'W1', inc: 180, exp: 0 }, { label: 'W2', inc: 220, exp: 80 }, { label: 'W3', inc: 380, exp: 400 }, { label: 'W4', inc: 340, exp: 0 }],
    transactions: [
      { id: 'feb1', kind: 'out', label: 'Sennheiser EW100',   sub: 'Neues Equipment',         amount: 680, date: '12.02.' },
      { id: 'feb2', kind: 'in',  label: 'Hochzeit Schmidt',   sub: 'Komplett-Set · 3 Tage',   amount: 380, date: '15.02.' },
      { id: 'feb3', kind: 'in',  label: 'Schulfest',          sub: 'PA · 1 Tag',              amount: 90,  date: '22.02.' },
    ],
  },
  '2026-03': { label: 'März 2026', short: 'Mär', income: 1840, expenses: 220,
    bars: [{ label: 'W1', inc: 240, exp: 0 }, { label: 'W2', inc: 380, exp: 120 }, { label: 'W3', inc: 750, exp: 0 }, { label: 'W4', inc: 470, exp: 100 }],
    transactions: [
      { id: 'mar1', kind: 'in',  label: 'Messeveranstaltung', sub: 'Komplett-Set · 5 Tage', amount: 750, date: '14.03.' },
      { id: 'mar2', kind: 'in',  label: 'Vereinsjubiläum',    sub: 'PA + Mikros',           amount: 320, date: '21.03.' },
      { id: 'mar3', kind: 'out', label: 'Kabel-Set',          sub: 'Verbrauchsmaterial',    amount: 120, date: '08.03.' },
      { id: 'mar4', kind: 'in',  label: 'Hochzeit Weber',     sub: '2 Tage',                amount: 280, date: '28.03.' },
    ],
  },
  '2026-04': { label: 'April 2026', short: 'Apr', income: 2100, expenses: 960,
    bars: [{ label: 'W1', inc: 380, exp: 0 }, { label: 'W2', inc: 580, exp: 880 }, { label: 'W3', inc: 620, exp: 0 }, { label: 'W4', inc: 520, exp: 80 }],
    transactions: [
      { id: 'apr1', kind: 'out', label: 'JBL SRX835P',        sub: 'Neues Equipment',       amount: 880, date: '11.04.' },
      { id: 'apr2', kind: 'in',  label: 'Open Air Festival',  sub: 'PA · 4 Tage',           amount: 720, date: '18.04.' },
      { id: 'apr3', kind: 'in',  label: 'Firmenevent Audi',   sub: 'Komplett · 2 Tage',     amount: 580, date: '24.04.' },
      { id: 'apr4', kind: 'out', label: 'Versicherung Q2',    sub: 'Geräte-Inhalt',         amount: 80,  date: '28.04.' },
    ],
  },
  '2026-05': { label: 'Mai 2026', short: 'Mai', income: 2480, expenses: 680,
    bars: [
      { label: 'Mo', inc: 0,   exp: 0 },   { label: 'Di', inc: 180, exp: 0 },
      { label: 'Mi', inc: 340, exp: 320 }, { label: 'Do', inc: 180, exp: 0 },
      { label: 'Fr', inc: 580, exp: 240 }, { label: 'Sa', inc: 760, exp: 0 },
      { label: 'So', inc: 440, exp: 120 },
    ],
    transactions: [
      { id: 'may1', kind: 'in',  label: 'Hochzeit Müller',     sub: 'JBL EON 712 · 4 Tage', amount: 180, date: '20.05.' },
      { id: 'may2', kind: 'in',  label: 'Vereinsfest TSV',     sub: 'SM58 Set · 2 Tage',    amount: 60,  date: '19.05.' },
      { id: 'may3', kind: 'out', label: 'Mikrofonständer ×4',  sub: 'König & Meyer',        amount: 240, date: '18.05.' },
      { id: 'may4', kind: 'in',  label: 'Open Air Konzert',    sub: 'Komplett-Set · 3 Tage', amount: 320, date: '17.05.' },
      { id: 'may5', kind: 'out', label: 'Kabelreparatur',      sub: 'Werkstatt Müller',     amount: 85,  date: '16.05.' },
      { id: 'may6', kind: 'in',  label: 'Geburtstag Klein',    sub: 'Anhänger · 1 Tag',     amount: 40,  date: '15.05.' },
      { id: 'may7', kind: 'out', label: 'Versicherung Anhänger', sub: 'Halbjährlich',       amount: 355, date: '14.05.' },
      { id: 'may8', kind: 'in',  label: 'Schulfest',           sub: 'JBL EON 712 · 1 Tag',  amount: 45,  date: '12.05.' },
    ],
  },
};

// Percent-change helper (returns null when previous = 0).
const pctF = (cur, prev) => {
  if (!prev) return null;
  const v = Math.round((cur - prev) / Math.abs(prev) * 100);
  return { val: Math.abs(v), up: v >= 0 };
};

function buildFinanceSummary(bars) {
  const cur = bars[bars.length - 1];
  const prev = bars[bars.length - 2] || { inc: 0, exp: 0 };
  const ytdInc = bars.reduce((s, b) => s + b.inc, 0);
  const ytdExp = bars.reduce((s, b) => s + b.exp, 0);
  return {
    income: cur.inc, expenses: cur.exp, net: cur.inc - cur.exp,
    prevNet: prev.inc - prev.exp, ytdInc, ytdExp, ytdNet: ytdInc - ytdExp,
  };
}

// ── Bar chart (hover tooltip) ──
function ChartBars({ bars }) {
  const t = useTheme();
  const p = finPalette(t);
  const max = Math.max(...bars.map((b) => Math.max(b.inc, b.exp)), 1);
  const H = 200;
  const [active, setActive] = useState(null);
  return (
    <div style={{ position: 'relative', height: H + 26 }}>
      {[0, 0.25, 0.5, 0.75, 1].map((g) => (
        <div key={g} style={{ position: 'absolute', left: 0, right: 0, top: H * (1 - g), borderTop: `0.5px ${g === 0 ? 'solid' : 'dashed'} ${p.grid}` }}/>
      ))}
      <div style={{ display: 'flex', alignItems: 'flex-end', gap: 14, height: H, position: 'relative' }}>
        {bars.map((bar, i) => {
          const isOn = active === i;
          const net = bar.inc - bar.exp;
          return (
            <div key={i} onMouseEnter={() => setActive(i)} onMouseLeave={() => setActive((v) => v === i ? null : v)}
              style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%', justifyContent: 'flex-end', position: 'relative', cursor: 'default' }}>
              <div style={{ width: '100%', display: 'flex', gap: 4, alignItems: 'flex-end', height: H, justifyContent: 'center' }}>
                <div style={{ width: '36%', height: `${bar.inc / max * 100}%`, background: isOn ? p.pos : p.posBar, borderRadius: '4px 4px 0 0', transition: 'background 0.15s' }}/>
                <div style={{ width: '36%', height: `${bar.exp / max * 100}%`, background: isOn ? p.neg : p.negBar, borderRadius: '4px 4px 0 0', transition: 'background 0.15s' }}/>
              </div>
              {isOn && (
                <div style={{ position: 'absolute', bottom: H + 10, left: '50%', transform: 'translateX(-50%)', background: t.card, color: t.text, border: `0.5px solid ${t.sep}`, borderRadius: 12, padding: '11px 13px', whiteSpace: 'nowrap', boxShadow: '0 8px 28px rgba(0,0,0,0.16)', zIndex: 8, pointerEvents: 'none', minWidth: 140 }}>
                  <div style={{ fontSize: 10, color: t.textSec, fontWeight: 700, letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: 7 }}>{bar.label} 2026</div>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 7, fontSize: 12.5, ...NUMS }}>
                    <span style={{ width: 7, height: 7, borderRadius: 4, background: p.pos }}/><span style={{ color: t.textSec }}>Einnahmen</span>
                    <span style={{ marginLeft: 'auto', color: t.text, fontWeight: 700 }}>+{bar.inc} €</span>
                  </div>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 7, fontSize: 12.5, marginTop: 4, ...NUMS }}>
                    <span style={{ width: 7, height: 7, borderRadius: 4, background: p.neg }}/><span style={{ color: t.textSec }}>Ausgaben</span>
                    <span style={{ marginLeft: 'auto', color: t.text, fontWeight: 700 }}>−{bar.exp} €</span>
                  </div>
                  <div style={{ height: 0.5, background: t.sep, margin: '8px -13px 7px' }}/>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12.5, ...NUMS }}>
                    <span style={{ color: t.textSec }}>Netto</span>
                    <span style={{ color: net >= 0 ? p.pos : p.neg, fontWeight: 700 }}>{net >= 0 ? '+' : '−'}{Math.abs(net)} €</span>
                  </div>
                  <div style={{ position: 'absolute', left: '50%', bottom: -5, transform: 'translateX(-50%) rotate(45deg)', width: 9, height: 9, background: t.card, borderRight: `0.5px solid ${t.sep}`, borderBottom: `0.5px solid ${t.sep}` }}/>
                </div>
              )}
            </div>
          );
        })}
      </div>
      <div style={{ display: 'flex', gap: 14, marginTop: 8 }}>
        {bars.map((bar, i) => <div key={i} style={{ flex: 1, fontSize: 11, color: active === i ? t.text : t.textSec, fontWeight: 600, textAlign: 'center', transition: 'color 0.15s' }}>{bar.label}</div>)}
      </div>
    </div>
  );
}

// ── Line chart (income vs expense) ──
function ChartLine({ bars }) {
  const t = useTheme();
  const p = finPalette(t);
  const max = Math.max(...bars.map((b) => Math.max(b.inc, b.exp)), 1);
  const W = 560, H = 200, pad = 10;
  const xs = (i) => i / (bars.length - 1 || 1) * (W - pad * 2) + pad;
  const ys = (v) => H - v / max * (H - pad * 2) - pad;
  const linePath = (key) => bars.map((b, i) => `${i === 0 ? 'M' : 'L'}${xs(i)} ${ys(b[key])}`).join(' ');
  const areaPath = `M${pad} ${H} ${bars.map((b, i) => `L${xs(i)} ${ys(b.inc)}`).join(' ')} L${W - pad} ${H} Z`;
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H + 22}`} style={{ display: 'block' }}>
      <defs><linearGradient id="incFillD" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor={p.pos} stopOpacity="0.2"/><stop offset="100%" stopColor={p.pos} stopOpacity="0"/></linearGradient></defs>
      {[0.25, 0.5, 0.75].map((g) => <line key={g} x1={pad} y1={H * g} x2={W - pad} y2={H * g} stroke={p.grid} strokeWidth="0.5" strokeDasharray="2 4"/>)}
      <line x1={pad} y1={H} x2={W - pad} y2={H} stroke={p.grid} strokeWidth="0.5"/>
      <path d={areaPath} fill="url(#incFillD)"/>
      <path d={linePath('inc')} fill="none" stroke={p.pos} strokeWidth="2.2" strokeLinejoin="round" strokeLinecap="round"/>
      <path d={linePath('exp')} fill="none" stroke={p.neg} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" strokeDasharray="4 4"/>
      {bars.map((b, i) => <circle key={i} cx={xs(i)} cy={ys(b.inc)} r="3" fill={p.pos}/>)}
      {bars.map((b, i) => <text key={i} x={xs(i)} y={H + 16} textAnchor="middle" fontSize="11" fill={t.textSec} fontWeight="600">{b.label}</text>)}
    </svg>
  );
}

// ── Cumulative net area ──
function ChartArea({ bars }) {
  const t = useTheme();
  const p = finPalette(t);
  let cum = 0;
  const nets = bars.map((b) => (cum += b.inc - b.exp, cum));
  const max = Math.max(...nets, 0), min = Math.min(...nets, 0);
  const range = max - min || 1;
  const W = 560, H = 200, pad = 10;
  const xs = (i) => i / (nets.length - 1 || 1) * (W - pad * 2) + pad;
  const ys = (v) => H - (v - min) / range * (H - pad * 2) - pad;
  const linePath = nets.map((v, i) => `${i === 0 ? 'M' : 'L'}${xs(i)} ${ys(v)}`).join(' ');
  const baseY = ys(0);
  const areaPath = `M${pad} ${baseY} ${nets.map((v, i) => `L${xs(i)} ${ys(v)}`).join(' ')} L${W - pad} ${baseY} Z`;
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H + 22}`} style={{ display: 'block' }}>
      <defs><linearGradient id="netFillD" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor={p.pos} stopOpacity="0.24"/><stop offset="100%" stopColor={p.pos} stopOpacity="0"/></linearGradient></defs>
      {[0.25, 0.5, 0.75].map((g) => <line key={g} x1={pad} y1={H * g} x2={W - pad} y2={H * g} stroke={p.grid} strokeWidth="0.5" strokeDasharray="2 4"/>)}
      <line x1={pad} y1={baseY} x2={W - pad} y2={baseY} stroke={p.grid} strokeWidth="0.5"/>
      <path d={areaPath} fill="url(#netFillD)"/>
      <path d={linePath} fill="none" stroke={p.pos} strokeWidth="2.2" strokeLinejoin="round" strokeLinecap="round"/>
      {nets.map((v, i) => <circle key={i} cx={xs(i)} cy={ys(v)} r="3" fill={p.pos}/>)}
      {bars.map((b, i) => <text key={i} x={xs(i)} y={H + 16} textAnchor="middle" fontSize="11" fill={t.textSec} fontWeight="600">{b.label}</text>)}
    </svg>
  );
}

// ── Donut (income / expense split) ──
function ChartDonut({ income, expenses, net }) {
  const t = useTheme();
  const p = finPalette(t);
  const total = income + expenses || 1;
  const incPct = income / total;
  const C = 100, R = 78, SW = 16, gap = 3;
  const circ = 2 * Math.PI * R;
  return (
    <div style={{ height: 200, position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <svg width={200} height={200} viewBox="0 0 200 200">
        <g transform={`rotate(-90 ${C} ${C})`}>
          <circle cx={C} cy={C} r={R} fill="none" stroke={p.grid} strokeWidth={SW}/>
          <circle cx={C} cy={C} r={R} fill="none" stroke={p.pos} strokeWidth={SW} strokeDasharray={`${Math.max(0, incPct * circ - gap)} ${circ}`} strokeLinecap="round"/>
          <circle cx={C} cy={C} r={R} fill="none" stroke={p.neg} strokeWidth={SW} strokeDasharray={`${Math.max(0, (1 - incPct) * circ - gap)} ${circ}`} strokeDashoffset={-(incPct * circ)} strokeLinecap="round"/>
        </g>
      </svg>
      <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', textAlign: 'center' }}>
        <div style={{ fontSize: 10, color: t.textSec, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.8 }}>Netto</div>
        <div style={{ fontSize: 26, fontWeight: 700, color: t.text, letterSpacing: -0.6, marginTop: 3, ...NUMS }}>{net >= 0 ? '+' : ''}{net.toLocaleString('de-DE')} €</div>
        <div style={{ fontSize: 10.5, color: t.textSec, marginTop: 3, ...NUMS }}>{Math.round(incPct * 100)}% Ein · {Math.round((1 - incPct) * 100)}% Aus</div>
      </div>
    </div>
  );
}

Object.assign(window, { NUMS, finPalette, FIN_BARS, SEED_TX, MONTHS_DETAIL, CURRENT_MONTH_KEY, pctF, buildFinanceSummary, ChartBars, ChartLine, ChartArea, ChartDonut });
