// ===== Auftragsanalyse — Diagramm-Bausteine =====
const { useState: useOcS } = React;

const ACCENT = '#3269B4';
const ACCENT_D = '#3269B4';
const GOLD = '#E0A53B';
const GREY = '#C9C7C3';

// Einheitliche Diagrammhöhe (Design Guide)
const CHART_BODY_H = 188;

// SVG einer Karte als PNG speichern
function saveCardImage(bodyEl, title) {
  const svg = bodyEl && bodyEl.querySelector('svg');
  if (!svg) return;
  const clone = svg.cloneNode(true);
  const vb = (svg.getAttribute('viewBox') || '0 0 480 200').split(/\s+/).map(Number);
  const w = vb[2] || svg.clientWidth || 480, h = vb[3] || svg.clientHeight || 200;
  clone.setAttribute('width', w); clone.setAttribute('height', h);
  clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  // CSS-Variablen auflösen
  const cs = getComputedStyle(document.body);
  let s = new XMLSerializer().serializeToString(clone);
  s = s.replace(/var\((--[a-z0-9-]+)\)/gi, (m, v) => cs.getPropertyValue(v).trim() || '#888');
  const scale = 2;
  const canvas = document.createElement('canvas'); canvas.width = w * scale; canvas.height = h * scale;
  const ctx = canvas.getContext('2d'); ctx.scale(scale, scale); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, w, h);
  const img = new Image();
  img.onload = () => {
    ctx.drawImage(img, 0, 0, w, h);
    canvas.toBlob(b => { const a = document.createElement('a'); a.href = URL.createObjectURL(b); a.download = (title || 'diagramm').replace(/[^\wäöü-]+/gi, '_') + '.png'; a.click(); });
  };
  img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(s)));
}

// Karten-Hülle mit Titel + Subwert (M / SD) + Werkzeug-Icons — alle Karten gleich hoch
function ChartCard({ title, sub, children, onReset }) {
  const bodyRef = React.useRef(null);
  const [maxed, setMaxed] = useOcS(false);
  const tools = (
    <div style={{ display: 'flex', alignItems: 'center', gap: 2, flex: '0 0 auto' }}>
      {onReset && <button onClick={onReset} title="Filter zurücksetzen" style={ocToolBtn('var(--accent-ink)')}><Icon name="close" size={14} /></button>}
      <button onClick={() => saveCardImage(bodyRef.current, title)} title="Als Bild speichern" style={ocToolBtn()}><Icon name="download" size={14} /></button>
      <button onClick={() => setMaxed(true)} title="Vergrößern" style={ocToolBtn()}><Icon name="expand" size={14} /></button>
    </div>
  );
  return (
    <div style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 8, boxShadow: 'var(--shadow)', display: 'flex', flexDirection: 'column' }}
      onContextMenu={(e) => window.kikiMenu(e, { id: title, label: 'Widget · ' + title, kind: 'Diagramm' })}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '11px 12px 4px' }}>
        <span style={{ width: 15, height: 15, borderRadius: 99, border: '1.5px solid var(--line-2)', color: 'var(--muted)', fontSize: 10, display: 'grid', placeItems: 'center', flex: '0 0 auto' }}>i</span>
        <div style={{ flex: 1, textAlign: 'center', minWidth: 0 }}>
          <div style={{ fontWeight: 600, fontSize: 14 }}>{title}</div>
          {sub && <div className="num" style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--ink-2)', marginTop: 1, letterSpacing: '.02em' }}>{sub}</div>}
        </div>
        {tools}
      </div>
      <div ref={bodyRef} style={{ height: CHART_BODY_H, padding: '4px 12px 10px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{children}</div>
      {maxed && (
        <div onClick={() => setMaxed(false)} style={{ position: 'fixed', inset: 0, background: 'rgba(63,62,61,.4)', zIndex: 70, display: 'grid', placeItems: 'center', animation: 'rowIn .15s' }}>
          <div onClick={e => e.stopPropagation()} style={{ width: 'min(1100px, 92vw)', background: 'var(--panel)', borderRadius: 12, boxShadow: '0 24px 64px rgba(63,62,61,.3)', overflow: 'hidden' }}>
            <div style={{ display: 'flex', alignItems: 'center', padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
              <div><div style={{ fontWeight: 600, fontSize: 16 }}>{title}</div>{sub && <div className="num" style={{ fontFamily: 'var(--mono)', fontSize: 12.5, color: 'var(--ink-2)' }}>{sub}</div>}</div>
              <div style={{ marginLeft: 'auto', display: 'flex', gap: 4 }}>
                <button onClick={() => saveCardImage(bodyRef.current, title)} title="Als Bild speichern" style={ocToolBtn()}><Icon name="download" size={16} /></button>
                <button onClick={() => setMaxed(false)} title="Schließen" style={ocToolBtn()}><Icon name="close" size={16} /></button>
              </div>
            </div>
            <div style={{ height: 'min(560px, 64vh)', padding: 22, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{children}</div>
          </div>
        </div>
      )}
    </div>
  );
}
const ocToolBtn = (color) => ({ width: 24, height: 24, flex: '0 0 auto', border: 'none', background: 'transparent', cursor: 'pointer', color: color || 'var(--muted)', display: 'grid', placeItems: 'center', borderRadius: 5 });

// Mausrad-Zoom: liefert onWheel-Handler, der das Sichtfenster {s,e} (0..1) um die Cursorposition zoomt
window.ocWheelZoom = function (zoom, setZoom) {
  return (e) => {
    e.preventDefault();
    const rect = e.currentTarget.getBoundingClientRect();
    const px = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
    const cur = zoom.e - zoom.s;
    const focus = zoom.s + px * cur;
    const k = e.deltaY < 0 ? 1 / 1.18 : 1.18;           // hoch = rein, runter = raus
    let span = Math.min(1, Math.max(0.04, cur * k));
    let s = focus - px * span, en = s + span;
    if (s < 0) { s = 0; en = span; }
    if (en > 1) { en = 1; s = 1 - span; }
    if (span >= 0.999) { s = 0; en = 1; }
    setZoom({ s, e: en });
  };
};

// Donut (Statusverteilung / Termintreue) — Segmente klickbar zum Filtern
function Donut({ segments, centerLabel, centerSub, onSeg, activeIdx }) {
  const total = segments.reduce((s, x) => s + x.value, 0) || 1;
  const R = 52, r = 32, cx = 70, cy = 70;
  let acc = 0;
  const arc = (frac0, frac1) => {
    // Vollkreis (ein Segment = 100 %): als Ring zeichnen, sonst bricht der SVG-Bogen
    if (frac1 - frac0 >= 0.9999) {
      return `M${cx} ${cy - R} A${R} ${R} 0 1 1 ${cx - 0.01} ${cy - R} Z M${cx} ${cy - r} A${r} ${r} 0 1 0 ${cx - 0.01} ${cy - r} Z`;
    }
    const a0 = frac0 * 2 * Math.PI - Math.PI / 2, a1 = frac1 * 2 * Math.PI - Math.PI / 2;
    const x0 = cx + R * Math.cos(a0), y0 = cy + R * Math.sin(a0), x1 = cx + R * Math.cos(a1), y1 = cy + R * Math.sin(a1);
    const xi1 = cx + r * Math.cos(a1), yi1 = cy + r * Math.sin(a1), xi0 = cx + r * Math.cos(a0), yi0 = cy + r * Math.sin(a0);
    const large = (frac1 - frac0) > 0.5 ? 1 : 0;
    return `M${x0} ${y0} A${R} ${R} 0 ${large} 1 ${x1} ${y1} L${xi1} ${yi1} A${r} ${r} 0 ${large} 0 ${xi0} ${yi0} Z`;
  };
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 16, height: '100%' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {segments.map((s, i) => (
          <button key={i} onClick={onSeg ? () => onSeg(s, i) : undefined}
            style={{ display: 'inline-flex', alignItems: 'center', gap: 7, fontSize: 13, color: 'var(--ink-2)', border: 'none', background: activeIdx === i ? 'var(--accent)' : 'transparent', borderRadius: 6, padding: '3px 7px', cursor: onSeg ? 'pointer' : 'default', textAlign: 'left' }}>
            <span style={{ width: 13, height: 13, borderRadius: 3, background: s.color, flex: '0 0 auto' }} /> {s.label}
            <span className="num" style={{ fontFamily: 'var(--mono)', fontSize: 12.5, fontWeight: 600, color: 'var(--ink)', marginLeft: 2 }}>{s.value.toLocaleString('de-DE')}</span>
          </button>
        ))}
      </div>
      <div style={{ position: 'relative', marginLeft: 'auto' }}>
        <svg width="150" height="150" viewBox="0 0 140 140">
          {segments.map((s, i) => { const f0 = acc / total; acc += s.value; const f1 = acc / total; return s.value <= 0 ? null : <path key={i} d={arc(f0, f1)} fillRule="evenodd" fill={s.color} opacity={activeIdx != null && activeIdx !== i ? 0.4 : 1} style={{ cursor: onSeg ? 'pointer' : 'default' }} onClick={onSeg ? () => onSeg(s, i) : undefined} />; })}
        </svg>
        <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', textAlign: 'center', pointerEvents: 'none' }}>
          <div>
            <div className="num" style={{ fontFamily: 'var(--mono)', fontSize: 21, fontWeight: 700 }}>{centerLabel}</div>
            {centerSub && <div className="label" style={{ fontSize: 9.5 }}>{centerSub}</div>}
          </div>
        </div>
      </div>
    </div>
  );
}

// Histogramm aus Werten (automatische Klassen). onBar(min,max,label) → Tabelle filtern.
function Histogram({ values, unit, bins = 20, color = ACCENT, onBar, activeBin }) {
  const [zoom, setZoom] = useOcS({ s: 0, e: 1 });
  if (!values.length) return <Empty />;
  const fullMn = Math.min(...values), fullMx = Math.max(...values);
  const fullSpan = (fullMx - fullMn) || 1;
  const mn = fullMn + zoom.s * fullSpan, mx = fullMn + zoom.e * fullSpan;
  const span = (mx - mn) || 1;
  const vals = values.filter(v => v >= mn - 1e-9 && v <= mx + 1e-9);
  const bw = span / bins;
  const counts = Array(bins).fill(0);
  vals.forEach(v => { let b = Math.floor((v - mn) / bw); if (b >= bins) b = bins - 1; if (b < 0) b = 0; counts[b]++; });
  const cmax = Math.max(...counts) || 1;
  const W = 460, H = 188, padL = 46, padB = 40, padT = 12, padR = 10;
  const plotW = W - padL - padR, plotH = H - padT - padB;
  const bx = (i) => padL + (i / bins) * plotW;
  const yTicks = [0, 0.5, 1].map(f => Math.round(cmax * f));
  const labelStep = Math.ceil(bins / 7);
  const onWheel = window.ocWheelZoom(zoom, setZoom);
  return (
    <svg onWheel={onWheel} onDoubleClick={() => setZoom({ s: 0, e: 1 })} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: '100%', display: 'block', fontFamily: 'var(--mono)', cursor: (zoom.s > 0 || zoom.e < 1) ? 'zoom-out' : 'zoom-in' }}>
      {yTicks.map((t, i) => { const yy = padT + plotH * (1 - t / cmax); return <g key={i}><line x1={padL} y1={yy} x2={W - padR} y2={yy} stroke="var(--line)" strokeWidth="0.5" /><text x={padL - 6} y={yy + 4} textAnchor="end" style={{ fontSize: 11, fill: 'var(--muted)' }}>{t.toLocaleString('de-DE')}</text></g>; })}
      {counts.map((c, i) => {
        const h = (c / cmax) * plotH; const bmin = mn + i * bw, bmax = mn + (i + 1) * bw;
        const act = activeBin != null && activeBin === i;
        return <rect key={i} x={bx(i) + 1} y={padT + plotH - h} width={Math.max(plotW / bins - 1.5, 1)} height={h}
          fill={act ? GOLD : color} rx="1" style={{ cursor: onBar ? 'pointer' : 'default' }}
          onClick={onBar ? () => onBar(bmin, bmax, i, `${Math.round(bmin)}…${Math.round(bmax)} ${unit.replace('in ', '')}`) : undefined}>
          {onBar && <title>{`${c} Aufträge · ${Math.round(bmin)}…${Math.round(bmax)}`}</title>}
        </rect>;
      })}
      {counts.map((c, i) => i % labelStep === 0 ? <text key={'l' + i} x={bx(i) + (plotW / bins) / 2} y={H - 23} textAnchor="middle" style={{ fontSize: 10.5, fill: 'var(--muted)' }}>{Math.round(mn + i * bw)}</text> : null)}
      <text x={padL + plotW / 2} y={H - 5} textAnchor="middle" style={{ fontSize: 11, fill: 'var(--ink-2)' }}>{unit}</text>
      <text x={11} y={padT + plotH / 2} style={{ fontSize: 11, fill: 'var(--ink-2)' }} transform={`rotate(-90 11 ${padT + plotH / 2})`} textAnchor="middle">Anzahl</text>
    </svg>
  );
}

// Kumulative Linie (Plan-Ende vs Ist-Ende über Zeit) — „Rückstand"
function CumLine({ planDates, istDates }) {
  const [zoom, setZoom] = useOcS({ s: 0, e: 1 });
  const all = [...planDates, ...istDates].map(d => new Date(d + 'T00:00:00Z').getTime()).filter(Boolean);
  if (!all.length) return <Empty />;
  const fullMin = Math.min(...all), fullMax = Math.max(...all), fullSpan = (fullMax - fullMin) || 1;
  const tMin = fullMin + zoom.s * fullSpan, tMax = fullMin + zoom.e * fullSpan, span = (tMax - tMin) || 1;
  const W = 460, H = 188, padL = 50, padB = 40, padT = 12, padR = 12;
  const plotW = W - padL - padR, plotH = H - padT - padB;
  const cum = (dates) => {
    const ts = dates.map(d => new Date(d + 'T00:00:00Z').getTime()).filter(Boolean).sort((a, b) => a - b);
    return ts.map((t, i) => ({ t, n: i + 1 }));
  };
  const cp = cum(planDates), ci = cum(istDates);
  const nMax = Math.max(cp.length, ci.length) || 1;
  const x = (t) => padL + ((t - tMin) / span) * plotW;
  const y = (n) => padT + plotH * (1 - n / nMax);
  const clip = (arr) => arr.filter(p => p.t >= tMin - 1e-9 && p.t <= tMax + 1e-9);
  const path = (arr) => clip(arr).map((p, i) => `${i ? 'L' : 'M'}${x(p.t).toFixed(1)} ${y(p.n).toFixed(1)}`).join(' ');
  const ticks = []; for (let k = 0; k <= 5; k++) ticks.push(new Date(tMin + (span / 5) * k));
  const onWheel = window.ocWheelZoom(zoom, setZoom);
  return (
    <svg onWheel={onWheel} onDoubleClick={() => setZoom({ s: 0, e: 1 })} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: '100%', display: 'block', fontFamily: 'var(--mono)', cursor: (zoom.s > 0 || zoom.e < 1) ? 'zoom-out' : 'zoom-in' }}>
      {[0, 0.5, 1].map((f, i) => { const yy = padT + plotH * (1 - f); return <g key={i}><line x1={padL} y1={yy} x2={W - padR} y2={yy} stroke="var(--line)" strokeWidth="0.5" /><text x={padL - 6} y={yy + 4} textAnchor="end" style={{ fontSize: 11, fill: 'var(--muted)' }}>{Math.round(nMax * f).toLocaleString('de-DE')}</text></g>; })}
      <path d={path(cp)} fill="none" stroke={GREY} strokeWidth="3" />
      <path d={path(ci)} fill="none" stroke={ACCENT} strokeWidth="2.4" />
      {ticks.map((t, i) => <text key={i} x={x(t.getTime())} y={H - 20} textAnchor="middle" style={{ fontSize: 10.5, fill: 'var(--muted)' }}>{t.toLocaleDateString('de-DE', { month: '2-digit', year: '2-digit' })}</text>)}
      <text x={padL + plotW / 2} y={H - 5} textAnchor="middle" style={{ fontSize: 11, fill: 'var(--ink-2)' }}>kumulierte Aufträge je Datum</text>
      <g transform={`translate(${padL + 6} ${padT + 4})`}>
        <line x1="0" y1="0" x2="16" y2="0" stroke={GREY} strokeWidth="3" /><text x="21" y="4" style={{ fontSize: 11, fill: 'var(--ink-2)' }}>Plan-Ende (Soll)</text>
        <line x1="0" y1="15" x2="16" y2="15" stroke={ACCENT} strokeWidth="2.4" /><text x="21" y="19" style={{ fontSize: 11, fill: 'var(--ink-2)' }}>Ist-Ende (fertig)</text>
      </g>
    </svg>
  );
}

function Empty() { return <div style={{ textAlign: 'center', color: 'var(--muted)', fontSize: 11.5 }}>Keine Daten im Filter</div>; }

// Balkendiagramm: mittlere Termintreue je ABC-Kunde (Anteil termintreu %) — klickbar
function ABCBars({ data, onBar, activeKey }) {
  if (!data || !data.length) return <Empty />;
  const W = 460, H = 188, padL = 50, padB = 40, padT = 14, padR = 12;
  const plotW = W - padL - padR, plotH = H - padT - padB;
  const n = data.length, slot = plotW / n, bw = Math.min(64, slot * 0.5);
  const y = (p) => padT + plotH * (1 - p / 100);
  const colFor = (abc) => abc === 'A' ? '#3269B4' : abc === 'B' ? '#5E86C4' : '#9FB6D8';
  return (
    <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: '100%', display: 'block', fontFamily: 'var(--mono)' }}>
      {[0, 25, 50, 75, 100].map((t, i) => { const yy = y(t); return <g key={i}><line x1={padL} y1={yy} x2={W - padR} y2={yy} stroke="var(--line)" strokeWidth="0.5" /><text x={padL - 6} y={yy + 4} textAnchor="end" style={{ fontSize: 11, fill: 'var(--muted)' }}>{t}</text></g>; })}
      {data.map((d, i) => {
        const cx = padL + slot * i + slot / 2, h = (d.pct / 100) * plotH;
        const act = activeKey === d.abc;
        return <g key={d.abc}>
          <rect x={cx - bw / 2} y={padT + plotH - h} width={bw} height={h} rx="2" fill={act ? GOLD : colFor(d.abc)} style={{ cursor: onBar ? 'pointer' : 'default' }} onClick={onBar ? () => onBar(d.abc) : undefined}>
            <title>{`${d.abc}-Kunden · ${d.pct}% termintreu (${d.ontime}/${d.total})`}</title>
          </rect>
          <text x={cx} y={padT + plotH - h - 5} textAnchor="middle" style={{ fontSize: 11, fontWeight: 700, fill: 'var(--ink)' }}>{d.pct}%</text>
          <text x={cx} y={H - 20} textAnchor="middle" style={{ fontSize: 12, fontWeight: 600, fill: 'var(--ink-2)' }}>{d.abc}-Kunden</text>
          <text x={cx} y={H - 6} textAnchor="middle" style={{ fontSize: 10, fill: 'var(--muted)' }}>n {d.total}</text>
        </g>;
      })}
      <text x={11} y={padT + plotH / 2} style={{ fontSize: 11, fill: 'var(--ink-2)' }} transform={`rotate(-90 11 ${padT + plotH / 2})`} textAnchor="middle">termintreu %</text>
    </svg>
  );
}

Object.assign(window, { ChartCard, Donut, Histogram, CumLine, ABCBars, CHART_BODY_H, AOChartColors: { ACCENT, ACCENT_D, GOLD, GREY } });
