// Chart primitives — minimal editorial style.
// SVG-based, sized responsively within their container.

const CH_MONO = '"JetBrains Mono", ui-monospace, monospace';

const PALETTE = {
  ink: '#1a1510',
  paper: '#f1ead8',
  paperLight: '#f8f2e1',
  paperSub: '#ede5d0',
  line: '#d4c8ae',
  rule: '#d4c8ae',
  muted: '#8a7d69',
  subtle: '#6f6556',
  accent: 'rgb(92, 158, 219)',
  olive:  'rgb(85, 107, 70)',
  red:    '#c47862',
  green:  '#7aa875',
  amber:  '#d8b46a',
  s1: '#1a1510',
  s2: 'rgb(92, 158, 219)',
  s3: 'rgb(85, 107, 70)',
};

function ChartCard({ title, subtitle, right, children, style = {} }) {
  return (
    <div style={{
      background: '#fffbf0',
      border: '1px solid #e6ddc9',
      borderRadius: 12,
      padding: 16,
      marginBottom: 12,
      ...style,
    }}>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
        marginBottom: 14, gap: 8,
      }}>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{
            fontFamily: CH_MONO, fontSize: 9.5, letterSpacing: 1.1,
            textTransform: 'uppercase', color: PALETTE.muted, marginBottom: 4,
          }}>{title}</div>
          {subtitle && (
            <div style={{ fontFamily: CH_MONO, fontSize: 11, color: PALETTE.subtle }}>{subtitle}</div>
          )}
        </div>
        {right}
      </div>
      {children}
    </div>
  );
}

function Legend({ items, compact = false }) {
  return (
    <div style={{
      display: 'flex', gap: compact ? 10 : 14, flexWrap: 'wrap',
      fontFamily: CH_MONO, fontSize: 9, letterSpacing: 0.6,
      textTransform: 'uppercase', color: PALETTE.subtle, marginTop: 8,
    }}>
      {items.map(it => (
        <div key={it.label} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <div style={{ width: 8, height: 8, borderRadius: 2, background: it.color }} />
          {it.label}
        </div>
      ))}
    </div>
  );
}

// Токен-перемикач (напр. ₴ / %)
function ValueToggle({ options, value, onChange }) {
  return (
    <div style={{
      display: 'inline-flex', background: '#ede5d0', padding: 2,
      borderRadius: 8,
    }}>
      {options.map(o => (
        <button key={o.id} onClick={() => onChange(o.id)} style={{
          padding: '4px 10px', borderRadius: 6,
          background: value === o.id ? '#fffbf0' : 'transparent',
          border: 'none', cursor: 'pointer',
          fontFamily: CH_MONO, fontSize: 9.5, letterSpacing: 0.8,
          textTransform: 'uppercase',
          color: value === o.id ? PALETTE.ink : PALETTE.muted,
          fontWeight: value === o.id ? 500 : 400,
        }}>{o.label}</button>
      ))}
    </div>
  );
}

function BigStat({ label, value, accent, hint, extra }) {
  return (
    <div style={{
      flex: 1, minWidth: 0, background: '#fffbf0',
      border: '1px solid #e6ddc9', borderRadius: 12,
      padding: '14px 14px 16px',
    }}>
      <div style={{
        fontFamily: CH_MONO, fontSize: 9, letterSpacing: 1,
        textTransform: 'uppercase', color: accent || PALETTE.muted,
      }}>{label}</div>
      <div style={{
        fontFamily: CH_MONO, fontSize: 22, lineHeight: 1.1,
        color: PALETTE.ink, letterSpacing: -0.5, marginTop: 8,
        wordBreak: 'break-word',
      }}>{value}</div>
      {hint && (
        <div style={{
          fontFamily: CH_MONO, fontSize: 9, color: PALETTE.subtle,
          marginTop: 4, letterSpacing: 0.4,
        }}>{hint}</div>
      )}
      {extra && <div style={{ marginTop: 10 }}>{extra}</div>}
    </div>
  );
}

// 33830 → "33 830"
function fmt(n) {
  return Math.round(n).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
function fmtPct(n, digits = 1) {
  const v = Number.isFinite(n) ? n : 0;
  return v.toFixed(digits).replace(/\.0$/, '') + '%';
}

// ─── BAR CHART (horizontal) ─────────────────────
// HTML-based (а не SVG) — бо треба щоб довгі числа ніколи не обрізались

// Плейсхолдер, коли графік не має даних, але ми не хочемо, щоб він «зникав».
function EmptyChart({ h = 140, msg = 'Немає даних за цей період' }) {
  return (
    <div style={{
      height: h, display:'flex', alignItems:'center', justifyContent:'center',
      border: `1px dashed ${PALETTE.line}`, borderRadius: 10,
      fontFamily: CH_MONO, fontSize: 10.5, color: PALETTE.subtle,
      background: PALETTE.paperLight, textAlign: 'center', padding: '0 16px',
      lineHeight: 1.5,
    }}>{msg}</div>
  );
}

function BarsH({ data, valueKey = 'value', labelKey = 'name', suffix = '', color = PALETTE.ink, showPct = false, formatter }) {
  if (!data || !data.length) return <EmptyChart h={120}/>;
  const max = Math.max(...data.map(d => d[valueKey]), 1);
  const fmtVal = formatter || (v => showPct ? fmtPct(v) : fmt(v) + (suffix || ''));
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {data.map((d, i) => {
        const w = Math.max(2, (d[valueKey] / max) * 100);
        return (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 8, fontFamily: CH_MONO, fontSize: 11 }}>
            <div style={{ minWidth: 78, flexShrink: 0, color: PALETTE.subtle, fontSize: 10, letterSpacing: 0.3 }}>
              {d[labelKey]}
            </div>
            <div style={{ flex: 1, height: 13, background: '#efe6d0', borderRadius: 2, position: 'relative', overflow: 'hidden' }}>
              <div style={{ width: w + '%', height: '100%', background: color, borderRadius: 2 }}/>
            </div>
            <div style={{ minWidth: 54, textAlign: 'right', flexShrink: 0, color: PALETTE.ink, fontSize: 10.5, fontWeight: 500 }}>
              {fmtVal(d[valueKey])}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─── VERTICAL BARS ─────────────────────
function BarsV({ data, keys = ['v'], colors = [PALETTE.ink], labelKey = 'month', h = 160, showVals = true, showY = false, isPct = false, formatter }) {
  if (!data || !data.length) return <EmptyChart h={h}/>;
  const fmtVal = formatter || (isPct ? (v => v.toFixed(1).replace(/\.0$/,'') + '%') : fmt);
  const totals = data.map(d => keys.reduce((s, k) => s + d[k], 0));
  const max = Math.max(...totals, 1) * 1.15;
  const topPad = 14;
  const botPad = 22;
  const leftPad = showY ? 34 : 20;
  const rightPad = 10;
  const plotW = 300 - leftPad - rightPad;
  const plotH = h - topPad - botPad;
  const bw = plotW / Math.max(data.length, 1);
  const gap = Math.max(2, bw * 0.18);

  // Y-шкала (3 рівні)
  const yTicks = showY ? [0, 0.5, 1].map(t => ({
    y: topPad + plotH - t * plotH,
    v: t * max,
  })) : [];

  // Підписи X: якщо багато — виводимо кожен 2й/3й
  const xSkip = data.length > 12 ? Math.ceil(data.length / 8) : 1;

  return (
    <svg width="100%" height={h} viewBox={`0 0 300 ${h}`} preserveAspectRatio="none">
      {/* Grid */}
      {showY && yTicks.map((t, i) => (
        <g key={i}>
          <line x1={leftPad} x2={300 - rightPad} y1={t.y} y2={t.y}
            stroke={PALETTE.line} strokeWidth="0.5" strokeDasharray="2 2"/>
          <text x={leftPad - 4} y={t.y + 3} fontSize="8" fontFamily={CH_MONO}
            fill={PALETTE.muted} textAnchor="end">
            {isPct ? fmtVal(t.v) : (t.v > 1000 ? Math.round(t.v/1000) + 'k' : fmt(t.v))}
          </text>
        </g>
      ))}
      {data.map((d, i) => {
        const x = leftPad + i * bw + gap / 2;
        const w = bw - gap;
        let yAcc = topPad + plotH;
        return (
          <g key={i}>
            {keys.map((k, ki) => {
              const seg = (d[k] / max) * plotH;
              yAcc -= seg;
              return <rect key={ki} x={x} y={yAcc} width={w} height={seg} fill={colors[ki]} />;
            })}
            {showVals && totals[i] > 0 && (
              <text x={x + w / 2} y={topPad + plotH - totals[i] / max * plotH - 4}
                fontSize="8.5" fontFamily={CH_MONO} fill={PALETTE.ink}
                textAnchor="middle">{fmtVal(totals[i])}</text>
            )}
            {(i % xSkip === 0 || i === data.length - 1) && (
              <text x={x + w / 2} y={h - 4}
                fontSize="9" fontFamily={CH_MONO} fill={PALETTE.subtle}
                textAnchor="middle">{d[labelKey]}</text>
            )}
          </g>
        );
      })}
    </svg>
  );
}

// ─── LINE / AREA CHART з мітками місяців ─────────────────
// data: number[] АБО [{v, start: Date}, ...]
function AreaChart({ data, h = 140, color = PALETTE.ink, monthTicks = true, showY = false, showPeaks = false, peakFormatter }) {
  if (!data || !data.length) return <EmptyChart h={h}/>;
  const isObj = typeof data[0] === 'object';
  const values = isObj ? data.map(d => d.v) : data;
  const starts = isObj ? data.map(d => d.start) : null;
  const max = Math.max(...values, 1) * 1.1;
  const topPad = 8;
  const botPad = 22;
  const leftPad = showY ? 32 : 20;
  const rightPad = 10;
  const plotW = 300 - leftPad - rightPad;
  const plotH = h - topPad - botPad;
  const pts = values.map((v, i) => [
    leftPad + (values.length === 1 ? plotW/2 : (i / (values.length - 1)) * plotW),
    topPad + plotH - (v / max) * (plotH - 4),
  ]);
  const path = pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p[0]},${p[1]}`).join(' ');
  const baseY = topPad + plotH;
  const area = path + ` L${pts[pts.length - 1][0]},${baseY} L${pts[0][0]},${baseY} Z`;

  const yTicks = showY ? [0, 0.5, 1].map(t => ({
    y: topPad + plotH - t * (plotH - 4),
    v: t * max,
  })) : [];

  // Мітки місяців — не частіше кожних 30px
  const MONTH_UA = ['січ','лют','бер','кві','тра','чер','лип','сер','вер','жов','лис','гру'];
  const monthLabels = [];
  if (monthTicks && starts) {
    let prevMonth = -1;
    let lastX = -40;
    starts.forEach((s, i) => {
      if (!(s instanceof Date)) return;
      const m = s.getMonth();
      if (m !== prevMonth && pts[i][0] - lastX >= 30) {
        monthLabels.push({ i, label: MONTH_UA[m], x: pts[i][0] });
        lastX = pts[i][0];
        prevMonth = m;
      } else if (m !== prevMonth) {
        prevMonth = m;
      }
    });
  }

  return (
    <svg width="100%" height={h} viewBox={`0 0 300 ${h}`} preserveAspectRatio="none">
      {showY ? yTicks.map((t, i) => (
        <g key={i}>
          <line x1={leftPad} x2={300-rightPad} y1={t.y} y2={t.y}
            stroke={PALETTE.line} strokeWidth="0.5" strokeDasharray="2 2"/>
          <text x={leftPad-4} y={t.y+3} fontSize="8" fontFamily={CH_MONO}
            fill={PALETTE.muted} textAnchor="end">
            {t.v > 1000 ? Math.round(t.v/1000) + 'k' : fmt(t.v)}
          </text>
        </g>
      )) : [0.25, 0.5, 0.75].map(t => (
        <line key={t} x1={leftPad} x2={300-rightPad} y1={topPad + plotH - t * (plotH - 4)} y2={topPad + plotH - t * (plotH - 4)}
          stroke={PALETTE.line} strokeWidth="0.5" strokeDasharray="2 2" />
      ))}
      <path d={area} fill={color} fillOpacity="0.12" />
      <path d={path} fill="none" stroke={color} strokeWidth="1.5" />
      {pts.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r="2" fill={color} />)}
      {showPeaks && pts.map((p, i) => {
        const v = values[i];
        if (v <= 0) return null;
        const prev = values[i - 1] ?? -Infinity;
        const next = values[i + 1] ?? -Infinity;
        // Показуємо тільки на ВИРАЗНИХ локальних максимумах (строго більше сусідів)
        // і на першій/останній точці якщо вона — максимум
        const isPeak = (v > prev && v >= next) || (v >= prev && v > next);
        if (!isPeak) return null;
        const label = peakFormatter ? peakFormatter(v) : fmt(v);
        return (
          <text key={'pk' + i} x={p[0]} y={p[1] - 5}
            fontSize="8.5" fontFamily={CH_MONO} fill={PALETTE.ink}
            fontWeight="600" textAnchor="middle">{label}</text>
        );
      })}
      {monthLabels.map((m, i) => (
        <g key={i}>
          <line x1={m.x} x2={m.x} y1={baseY} y2={baseY + 3} stroke={PALETTE.muted} strokeWidth="0.6"/>
          <text x={m.x} y={h - 2} fontSize="8.5" fontFamily={CH_MONO}
            fill={PALETTE.subtle} textAnchor="middle">{m.label}</text>
        </g>
      ))}
    </svg>
  );
}

// ─── TWO-SERIES BARS (для порівняльних графіків, наприклад візити vs чеки) ─
function BarsV2({ data, keyA, keyB, labelA, labelB, colorA, colorB, labelKey = 'month', h = 160 }) {
  if (!data || !data.length) return <EmptyChart h={h}/>;
  const max = Math.max(...data.flatMap(d => [d[keyA], d[keyB]]), 1) * 1.15;
  const pad = 30;
  const plotH = h - pad - 14;
  const groupW = 260 / Math.max(data.length, 1);
  const gap = groupW * 0.12;
  const bw = (groupW - gap) / 2;
  return (
    <div>
      <svg width="100%" height={h} viewBox={`0 0 300 ${h}`} preserveAspectRatio="none">
        {data.map((d, i) => {
          const x0 = 20 + i * groupW + gap / 2;
          const hA = (d[keyA] / max) * plotH;
          const hB = (d[keyB] / max) * plotH;
          return (
            <g key={i}>
              <rect x={x0} y={plotH - hA} width={bw} height={hA} fill={colorA}/>
              <rect x={x0 + bw} y={plotH - hB} width={bw} height={hB} fill={colorB}/>
              <text x={x0 + bw} y={h - 4} fontSize="9" fontFamily={CH_MONO}
                fill={PALETTE.subtle} textAnchor="middle">{d[labelKey]}</text>
            </g>
          );
        })}
      </svg>
      <Legend items={[{ label: labelA, color: colorA }, { label: labelB, color: colorB }]}/>
    </div>
  );
}

function Donut({ data, size = 140, colors }) {
  const total = data.reduce((s, d) => s + d.pct, 0);
  const cx = size / 2, cy = size / 2;
  const r = size / 2 - 4, rInner = r - 18;
  let a = -Math.PI / 2;
  const arcs = data.map((d, i) => {
    const frac = d.pct / total;
    const a2 = a + frac * Math.PI * 2;
    const large = frac > 0.5 ? 1 : 0;
    const x1 = cx + Math.cos(a) * r, y1 = cy + Math.sin(a) * r;
    const x2 = cx + Math.cos(a2) * r, y2 = cy + Math.sin(a2) * r;
    const x3 = cx + Math.cos(a2) * rInner, y3 = cy + Math.sin(a2) * rInner;
    const x4 = cx + Math.cos(a) * rInner, y4 = cy + Math.sin(a) * rInner;
    const d_ = `M${x1},${y1} A${r},${r} 0 ${large} 1 ${x2},${y2} L${x3},${y3} A${rInner},${rInner} 0 ${large} 0 ${x4},${y4} Z`;
    a = a2;
    return <path key={i} d={d_} fill={colors[i]} />;
  });
  return <svg width={size} height={size}>{arcs}</svg>;
}

// ─── BARS V + PLAN TICK ────────────────────────
// Кожен бар має реальне значення (`total`) та мітку плану (`plan`).
// Майбутні місяці (total=0) показуються як порожні колонки з лінією плану.
function BarsVWithPlan({ data, labelKey = 'month', h = 200, color = PALETTE.olive, planColor = PALETTE.red, formatter }) {
  if (!data || !data.length) return <EmptyChart h={h}/>;
  const fmtVal = formatter || fmt;
  const max = Math.max(...data.map(d => Math.max(d.total || 0, d.plan || 0)), 1) * 1.15;
  const topPad = 14;
  const botPad = 16;
  const plotH = h - topPad - botPad;
  const leftPad = 26;
  const rightPad = 6;
  const plotW = 300 - leftPad - rightPad;
  const bw = plotW / data.length;
  const gap = bw * 0.18;
  const ticks = [0.25, 0.5, 0.75, 1].map(t => ({ v: max * t, y: topPad + plotH - t * plotH }));

  // selection: { idx, kind: 'bar'|'plan' } | null
  const [sel, setSel] = React.useState(null);
  React.useEffect(() => {
    if (!sel) return;
    const onClick = () => setSel(null);
    // Закриваємо при кліку deinside документа (delayed щоб не закривався відразу)
    const t = setTimeout(() => document.addEventListener('click', onClick), 0);
    return () => { clearTimeout(t); document.removeEventListener('click', onClick); };
  }, [sel]);

  const selData = sel ? data[sel.idx] : null;
  const selValue = selData ? (sel.kind === 'plan' ? selData.plan : selData.total) : 0;
  const selX = sel ? leftPad + sel.idx * bw + bw / 2 : 0;
  const selY = sel
    ? (sel.kind === 'plan'
        ? topPad + plotH - (selData.plan / max) * plotH
        : topPad + plotH - (selData.total / max) * plotH)
    : 0;

  return (
    <svg width="100%" height={h} viewBox={`0 0 300 ${h}`} preserveAspectRatio="none"
      style={{ touchAction: 'manipulation' }}>
      {ticks.map((t, i) => (
        <g key={i}>
          <line x1={leftPad} x2={300 - rightPad} y1={t.y} y2={t.y}
            stroke={PALETTE.line} strokeWidth="0.5" strokeDasharray="2 2"/>
          <text x={leftPad - 4} y={t.y + 3} fontSize="8" fontFamily={CH_MONO}
            fill={PALETTE.muted} textAnchor="end">
            {t.v > 1000 ? Math.round(t.v / 1000) + 'k' : fmt(Math.round(t.v))}
          </text>
        </g>
      ))}
      {data.map((d, i) => {
        const x = leftPad + i * bw + gap / 2;
        const w = bw - gap;
        const total = d.total || 0;
        const plan = d.plan || 0;
        const barH = (total / max) * plotH;
        const barY = topPad + plotH - barH;
        const planY = topPad + plotH - (plan / max) * plotH;
        const future = total === 0 && plan > 0;
        return (
          <g key={i}>
            {future && (
              <rect x={x} y={planY} width={w} height={topPad + plotH - planY}
                fill="none" stroke={PALETTE.line} strokeWidth="1" strokeDasharray="2 2" rx="1"/>
            )}
            {total > 0 && (
              <rect x={x} y={barY} width={w} height={barH} fill={color} rx="1"
                style={{ cursor: 'pointer' }}
                onClick={(e) => { e.stopPropagation(); setSel({ idx: i, kind: 'bar' }); }}/>
            )}
            {plan > 0 && (
              <>
                {/* видима лінія плану */}
                <line x1={x - 1} x2={x + w + 1} y1={planY} y2={planY}
                  stroke={planColor} strokeWidth="1.6" strokeLinecap="round"/>
                {/* невидимий клік-зона, щоб легше тицяти на лінію */}
                <line x1={x - 1} x2={x + w + 1} y1={planY} y2={planY}
                  stroke="transparent" strokeWidth="12" strokeLinecap="round"
                  style={{ cursor: 'pointer' }}
                  onClick={(e) => { e.stopPropagation(); setSel({ idx: i, kind: 'plan' }); }}/>
              </>
            )}
            <text x={x + w / 2} y={h - 4}
              fontSize="8.5" fontFamily={CH_MONO} fill={PALETTE.subtle}
              textAnchor="middle"
              style={{ pointerEvents: 'none' }}>{d[labelKey]}</text>
          </g>
        );
      })}
      {/* tooltip після кліку */}
      {sel && selValue > 0 && (() => {
        const txt = (sel.kind === 'plan' ? 'план ' : '') + fmtVal(Math.round(selValue)) + ' €';
        const tw = Math.max(36, txt.length * 5.5);
        const tx = Math.max(leftPad + 2, Math.min(300 - rightPad - tw - 2, selX - tw / 2));
        const ty = Math.max(topPad + 2, selY - 18);
        return (
          <g pointerEvents="none">
            <rect x={tx} y={ty} width={tw} height={14} rx="3"
              fill={sel.kind === 'plan' ? planColor : PALETTE.ink}/>
            <text x={tx + tw / 2} y={ty + 10} fontSize="9" fontFamily={CH_MONO}
              fill="#fffbf0" textAnchor="middle" fontWeight="500">{txt}</text>
          </g>
        );
      })()}
    </svg>
  );
}

// ─── MiniBarWithLine ──────────────────────
// Горизонтальний бар з прогресом + червона лінія "очікувано сьогодні" + замок при 100%.
function MiniBarWithLine({ value, plan, expectedRatio, color, height = 14, reward }) {
  const c = color || PALETTE.ink;
  const ratio = plan > 0 ? Math.min(1.5, value / plan) : 0;
  const fillW = Math.min(100, ratio * 100);
  const overflow = ratio > 1;
  const expectedPct = expectedRatio != null ? Math.min(100, expectedRatio * 100) : null;
  const unlocked = plan > 0 && value >= plan;
  const lockSize = Math.max(10, Math.round(height * 0.85));
  return (
    <div style={{ position:'relative', paddingRight: lockSize + 4 }}>
      <div style={{
        position:'relative', height,
        background: PALETTE.paperSub, borderRadius: 4,
        overflow: 'visible',
        border: `1px solid ${PALETTE.line}`,
      }}>
        <div style={{ position:'absolute', inset:0, borderRadius:3, overflow:'hidden' }}>
          <div style={{
            width: fillW + '%', height: '100%',
            background: overflow || unlocked ? PALETTE.green : c,
            borderRadius: 3,
            transition: 'width 0.5s cubic-bezier(0.22,1,0.36,1), background 0.3s',
          }}/>
        </div>
        {expectedPct != null && plan > 0 && (
          <div title={`Очікувано сьогодні: ${expectedPct.toFixed(0)}%`} style={{
            position:'absolute', top:-2, bottom:-2,
            left: `calc(${expectedPct}% - 1px)`,
            width: 2, background: PALETTE.red,
            boxShadow: '0 0 0 1.5px rgba(196,120,98,0.25)',
            zIndex: 2,
          }}/>
        )}
        {unlocked && reward && (
          <div style={{
            position:'absolute', inset: 0,
            display:'flex', alignItems:'center', paddingLeft: 8, paddingRight: 4,
            fontFamily: CH_MONO, fontSize: Math.max(8.5, height * 0.42),
            color: '#fffbf0', fontWeight: 600, letterSpacing: 0.4,
            textTransform: 'uppercase', textShadow: '0 1px 1px rgba(0,0,0,0.25)',
            pointerEvents: 'none', zIndex: 3,
            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          }}>★ {reward}</div>
        )}
      </div>
      {/* Lock icon at 100% mark */}
      <div style={{
        position:'absolute', right: 0, top: '50%', transform:'translateY(-50%)',
        width: lockSize, height: lockSize, pointerEvents:'none',
      }}>
        <svg width={lockSize} height={lockSize} viewBox="0 0 24 24" style={{ display:'block' }}>
          {unlocked ? (
            <path d="M 7 11 V 7 a 5 5 0 0 1 10 0 V 9"
              fill="none" stroke="#1a1510" strokeWidth={2.4} strokeLinecap="round"
              transform="translate(2 -3) rotate(15 12 7)"/>
          ) : (
            <path d="M 7 11 V 8 a 5 5 0 0 1 10 0 V 11"
              fill="none" stroke="#1a1510" strokeWidth={2.4} strokeLinecap="round"/>
          )}
          <rect x={4} y={11} width={16} height={10} rx={2}
            fill="#1a1510" stroke="#0a0805" strokeWidth={0.8}/>
          <circle cx={12} cy={15} r={1.4} fill={PALETTE.amber}/>
          <rect x={11.4} y={15.2} width={1.2} height={3} fill={PALETTE.amber}/>
        </svg>
      </div>
    </div>
  );
}

// ─── BARS V КРОС-ПРОДАЖІ ────────────────────
// Бари — продажі товарів в ремонтних чеках.
// Зелена горизонтальна лінія на рівні суми ремонтів.
// Всередині бару — коефіцієнт (sales/repairs) вертикально.
// Клік по бару / лінії — відкриває табличку з сумою.
function BarsVCrossSell({ data, labelKey = 'month', h = 220, barColor = PALETTE.ink, lineColor = PALETTE.green }) {
  if (!data || !data.length) return <EmptyChart h={h}/>;
  const max = Math.max(...data.map(d => Math.max(d.sales || 0, d.repairs || 0)), 1) * 1.15;
  const topPad = 14;
  const botPad = 16;
  const plotH = h - topPad - botPad;
  const leftPad = 26;
  const rightPad = 6;
  const plotW = 300 - leftPad - rightPad;
  const bw = plotW / data.length;
  const gap = bw * 0.18;
  const ticks = [0.25, 0.5, 0.75, 1].map(t => ({ v: max * t, y: topPad + plotH - t * plotH }));

  const [sel, setSel] = React.useState(null);
  React.useEffect(() => {
    if (!sel) return;
    const onClick = () => setSel(null);
    const t = setTimeout(() => document.addEventListener('click', onClick), 0);
    return () => { clearTimeout(t); document.removeEventListener('click', onClick); };
  }, [sel]);

  const selData = sel ? data[sel.idx] : null;
  const selValue = selData ? (sel.kind === 'line' ? selData.repairs : selData.sales) : 0;
  const selX = sel ? leftPad + sel.idx * bw + bw / 2 : 0;
  const selY = sel
    ? (sel.kind === 'line'
        ? topPad + plotH - (selData.repairs / max) * plotH
        : topPad + plotH - (selData.sales / max) * plotH)
    : 0;

  return (
    <svg width="100%" height={h} viewBox={`0 0 300 ${h}`} preserveAspectRatio="none"
      style={{ touchAction: 'manipulation' }}>
      {ticks.map((t, i) => (
        <g key={i}>
          <line x1={leftPad} x2={300 - rightPad} y1={t.y} y2={t.y}
            stroke={PALETTE.line} strokeWidth="0.5" strokeDasharray="2 2"/>
          <text x={leftPad - 4} y={t.y + 3} fontSize="8" fontFamily={CH_MONO}
            fill={PALETTE.muted} textAnchor="end">
            {t.v > 1000 ? Math.round(t.v / 1000) + 'k' : fmt(Math.round(t.v))}
          </text>
        </g>
      ))}
      {data.map((d, i) => {
        const x = leftPad + i * bw + gap / 2;
        const w = bw - gap;
        const sales = d.sales || 0;
        const repairs = d.repairs || 0;
        const barH = (sales / max) * plotH;
        const barY = topPad + plotH - barH;
        const lineY = topPad + plotH - (repairs / max) * plotH;
        return (
          <g key={i}>
            {sales > 0 && (
              <rect x={x} y={barY} width={w} height={barH} fill={barColor} rx="1"
                style={{ cursor: 'pointer' }}
                onClick={(e) => { e.stopPropagation(); setSel({ idx: i, kind: 'bar' }); }}/>
            )}
            {repairs > 0 && (
              <>
                <line x1={x - 1} x2={x + w + 1} y1={lineY} y2={lineY}
                  stroke={lineColor} strokeWidth="1.8" strokeLinecap="round"/>
                <line x1={x - 1} x2={x + w + 1} y1={lineY} y2={lineY}
                  stroke="transparent" strokeWidth="12" strokeLinecap="round"
                  style={{ cursor: 'pointer' }}
                  onClick={(e) => { e.stopPropagation(); setSel({ idx: i, kind: 'line' }); }}/>
              </>
            )}
            {/* КОЕФІЦІЄНТ всередині бару */}
            {d.coef > 0 && barH > 28 && (
              <text x={x + w / 2} y={barY + barH / 2}
                fontSize="9.5" fontFamily={CH_MONO} fill="#fffbf0"
                textAnchor="middle" fontWeight="600"
                style={{ pointerEvents: 'none' }}>
                {d.coef.toFixed(1)}x
              </text>
            )}
            {/* якщо бар низький — показуємо коеф. НАД баром */}
            {d.coef > 0 && barH > 0 && barH <= 28 && (
              <text x={x + w / 2} y={barY - 3}
                fontSize="8.5" fontFamily={CH_MONO} fill={PALETTE.ink}
                textAnchor="middle" fontWeight="600"
                style={{ pointerEvents: 'none' }}>
                {d.coef.toFixed(1)}x
              </text>
            )}
            <text x={x + w / 2} y={h - 4}
              fontSize="8.5" fontFamily={CH_MONO} fill={PALETTE.subtle}
              textAnchor="middle"
              style={{ pointerEvents: 'none' }}>{d[labelKey]}</text>
          </g>
        );
      })}
      {sel && selValue > 0 && (() => {
        const label = sel.kind === 'line' ? 'ремонт ' : 'продаж ';
        const txt = label + fmt(Math.round(selValue)) + ' €';
        const tw = Math.max(48, txt.length * 5.5);
        const tx = Math.max(leftPad + 2, Math.min(300 - rightPad - tw - 2, selX - tw / 2));
        const ty = Math.max(topPad + 2, selY - 18);
        return (
          <g pointerEvents="none">
            <rect x={tx} y={ty} width={tw} height={14} rx="3"
              fill={sel.kind === 'line' ? lineColor : PALETTE.ink}/>
            <text x={tx + tw / 2} y={ty + 10} fontSize="9" fontFamily={CH_MONO}
              fill="#fffbf0" textAnchor="middle" fontWeight="500">{txt}</text>
          </g>
        );
      })()}
    </svg>
  );
}

window.CHARTS = { ChartCard, Legend, ValueToggle, BigStat, BarsH, BarsV, BarsV2, BarsVWithPlan, BarsVCrossSell, AreaChart, Donut, MiniBarWithLine, fmt, fmtPct, PALETTE };
