/* NINA — hand-built animated SVG charts.
   Bars grow from base, donut sweeps, line draws (stroke-dashoffset),
   gauge fills. All gated on useInView so they animate once on entry,
   and respect prefers-reduced-motion. */

const CHART_COLORS = ['#FF7A59', '#FBBF24', '#34D399', '#0EA5E9', '#A78BFA', '#FB7185', '#2DD4BF', '#F472B6'];
const REDUCED = () => window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

/* ---------------- Horizontal bars by category ---------------- */
function BarsByCategory({ data }) {
  const [ref, seen] = useInView();
  const max = Math.max(...data.map((d) => d.cents), 1);
  return (
    <div ref={ref} style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      {data.map((d, i) => {
        const pct = (d.cents / max) * 100;
        return (
          <div key={d.key} style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            <div className="row between" style={{ fontSize: 13 }}>
              <span style={{ fontWeight: 600 }}>
                <span style={{ marginRight: 8 }}>{d.emoji}</span>{d.name}
              </span>
              <span className="tnum" style={{ fontWeight: 700, color: 'var(--ink)' }}>{d.fmt}</span>
            </div>
            <div className="progress" style={{ height: 12, background: 'var(--surface-warm)' }}>
              <div style={{
                height: '100%', borderRadius: 999,
                width: (seen && !REDUCED()) ? pct + '%' : (REDUCED() ? pct + '%' : '0%'),
                background: CHART_COLORS[i % CHART_COLORS.length],
                transition: 'width 700ms cubic-bezier(0.22,1,0.36,1)',
                transitionDelay: (i * 60) + 'ms',
              }} />
            </div>
          </div>
        );
      })}
    </div>
  );
}

/* ---------------- Donut by method ---------------- */
function DonutByMethod({ data, centerLabel, centerValue }) {
  const [ref, seen] = useInView();
  const total = data.reduce((s, d) => s + d.cents, 0) || 1;
  const R = 70, C = 2 * Math.PI * R, sw = 26;
  let acc = 0;
  const segs = data.map((d, i) => {
    const frac = d.cents / total;
    const seg = { color: CHART_COLORS[i % CHART_COLORS.length], frac, offset: acc, ...d };
    acc += frac;
    return seg;
  });
  return (
    <div ref={ref} style={{ display: 'flex', alignItems: 'center', gap: 28, flexWrap: 'wrap', justifyContent: 'center' }}>
      <div style={{ position: 'relative', width: 184, height: 184, flex: 'none' }}>
        <svg width="184" height="184" viewBox="0 0 184 184">
          <circle cx="92" cy="92" r={R} fill="none" stroke="var(--surface-warm)" strokeWidth={sw} />
          {segs.map((s, i) => {
            const len = s.frac * C;
            const dash = (seen && !REDUCED()) || REDUCED() ? len : 0;
            return (
              <circle key={i} cx="92" cy="92" r={R} fill="none" stroke={s.color} strokeWidth={sw}
                strokeDasharray={`${dash} ${C - dash + 0.001}`}
                strokeDashoffset={-s.offset * C}
                strokeLinecap="butt"
                transform="rotate(-90 92 92)"
                style={{ transition: 'stroke-dasharray 800ms cubic-bezier(0.22,1,0.36,1)', transitionDelay: (i * 90) + 'ms' }} />
            );
          })}
        </svg>
        <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', textAlign: 'center' }}>
          <div>
            <div style={{ fontSize: 11, color: 'var(--subtle)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.05em' }}>{centerLabel}</div>
            <div className="serif tnum" style={{ fontSize: 19, fontWeight: 600, whiteSpace: 'nowrap' }}>{centerValue}</div>
          </div>
        </div>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 150 }}>
        {segs.map((s, i) => (
          <div key={i} className="row between" style={{ fontSize: 13 }}>
            <span className="row" style={{ gap: 8 }}>
              <span style={{ width: 10, height: 10, borderRadius: 3, background: s.color }} />
              <span style={{ fontWeight: 600 }}>{s.label}</span>
            </span>
            <span className="muted tnum" style={{ fontWeight: 600 }}>{Math.round(s.frac * 100)}%</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------------- Trend line (30d) — draws + area fill + hover ---------------- */
function TrendLine({ data, height = 220 }) {
  const [ref, seen] = useInView();
  const [hover, setHover] = useState(null);
  const W = 720, H = height, padX = 8, padY = 24;
  const maxE = Math.max(...data.map((d) => Math.max(d.expenseCents, d.incomeCents)), 1);
  const x = (i) => padX + (i / (data.length - 1)) * (W - padX * 2);
  const y = (c) => H - padY - (c / maxE) * (H - padY * 2);
  const linePath = (key) => data.map((d, i) => `${i === 0 ? 'M' : 'L'} ${x(i).toFixed(1)} ${y(d[key]).toFixed(1)}`).join(' ');
  const areaPath = `${data.map((d, i) => `${i === 0 ? 'M' : 'L'} ${x(i).toFixed(1)} ${y(d.expenseCents).toFixed(1)}`).join(' ')} L ${x(data.length - 1)} ${H - padY} L ${x(0)} ${H - padY} Z`;
  const drawn = (seen && !REDUCED()) || REDUCED();

  return (
    <div ref={ref} style={{ position: 'relative', width: '100%' }}>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} preserveAspectRatio="none"
        onMouseLeave={() => setHover(null)}
        onMouseMove={(e) => {
          const r = e.currentTarget.getBoundingClientRect();
          const rel = ((e.clientX - r.left) / r.width) * W;
          let idx = Math.round(((rel - padX) / (W - padX * 2)) * (data.length - 1));
          idx = Math.max(0, Math.min(data.length - 1, idx));
          setHover(idx);
        }}>
        <defs>
          <linearGradient id="areaFill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#FF7A59" stopOpacity="0.22" />
            <stop offset="100%" stopColor="#FF7A59" stopOpacity="0" />
          </linearGradient>
        </defs>
        {/* gridlines */}
        {[0.25, 0.5, 0.75].map((g) => (
          <line key={g} x1={padX} x2={W - padX} y1={padY + g * (H - padY * 2)} y2={padY + g * (H - padY * 2)}
            stroke="var(--line)" strokeWidth="1" strokeDasharray="3 4" />
        ))}
        {/* area */}
        <path d={areaPath} fill="url(#areaFill)" style={{ opacity: drawn ? 1 : 0, transition: 'opacity 600ms ease 300ms' }} />
        {/* income (mint) */}
        <path d={linePath('incomeCents')} fill="none" stroke="#34D399" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
          strokeDasharray="2000" strokeDashoffset={drawn ? 0 : 2000}
          style={{ transition: 'stroke-dashoffset 1100ms cubic-bezier(0.22,1,0.36,1)' }} />
        {/* expense (coral) */}
        <path d={linePath('expenseCents')} fill="none" stroke="#E14E2E" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"
          strokeDasharray="2000" strokeDashoffset={drawn ? 0 : 2000}
          style={{ transition: 'stroke-dashoffset 1100ms cubic-bezier(0.22,1,0.36,1)' }} />
        {/* hover marker */}
        {hover != null && (
          <g>
            <line x1={x(hover)} x2={x(hover)} y1={padY} y2={H - padY} stroke="var(--coral)" strokeWidth="1" strokeDasharray="3 3" />
            <circle cx={x(hover)} cy={y(data[hover].expenseCents)} r="5" fill="#E14E2E" stroke="#fff" strokeWidth="2" />
          </g>
        )}
      </svg>
      {/* hover tooltip */}
      {hover != null && (
        <div style={{
          position: 'absolute', top: 4, left: `calc(${(x(hover) / W) * 100}% )`, transform: 'translateX(-50%)',
          background: 'var(--ink)', color: '#fff', padding: '6px 10px', borderRadius: 10, fontSize: 11, whiteSpace: 'nowrap',
          pointerEvents: 'none', boxShadow: 'var(--shadow-md)',
        }}>
          <div style={{ fontWeight: 700, marginBottom: 2 }}>{data[hover].label}</div>
          <div className="tnum">Gasto {data[hover].expenseFmt}</div>
        </div>
      )}
      {/* x labels */}
      <div className="row between" style={{ fontSize: 11, color: 'var(--subtle)', marginTop: 4 }}>
        <span>{data[0].label}</span>
        <span>{data[Math.floor(data.length / 2)].label}</span>
        <span>{data[data.length - 1].label}</span>
      </div>
    </div>
  );
}

/* ---------------- Card limit gauge (semicircle) ---------------- */
function CardGauge({ pct, color }) {
  const [ref, seen] = useInView();
  const R = 54, C = Math.PI * R; // semicircle length
  const clamped = Math.min(100, pct);
  const drawn = (seen && !REDUCED()) || REDUCED();
  const len = (clamped / 100) * C;
  return (
    <div ref={ref} style={{ position: 'relative', width: 140, height: 84 }}>
      <svg width="140" height="84" viewBox="0 0 140 84">
        <path d="M 16 76 A 54 54 0 0 1 124 76" fill="none" stroke="var(--surface-warm)" strokeWidth="14" strokeLinecap="round" />
        <path d="M 16 76 A 54 54 0 0 1 124 76" fill="none" stroke={color || 'var(--coral)'} strokeWidth="14" strokeLinecap="round"
          strokeDasharray={`${drawn ? len : 0} ${C}`}
          style={{ transition: 'stroke-dasharray 900ms cubic-bezier(0.22,1,0.36,1)' }} />
      </svg>
      <div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, textAlign: 'center' }}>
        <div className="serif tnum" style={{ fontSize: 24, fontWeight: 600, lineHeight: 1 }}>{pct}%</div>
        <div style={{ fontSize: 11, color: 'var(--subtle)', fontWeight: 600 }}>usado</div>
      </div>
    </div>
  );
}

/* ---------------- Mini sparkline (cards mini-usage) ---------------- */
function Sparkline({ values, color }) {
  const W = 100, H = 32;
  const max = Math.max(...values, 1);
  const pts = values.map((v, i) => `${(i / (values.length - 1)) * W},${H - (v / max) * (H - 4) - 2}`).join(' ');
  return (
    <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} style={{ display: 'block' }}>
      <polyline points={pts} fill="none" stroke={color || 'var(--coral)'} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

/* ---------------- Vertical bars (daily counts) ---------------- */
function VBars({ data, height = 140, color }) {
  const [ref, seen] = useInView();
  const max = Math.max(...data.map((d) => d.count), 1);
  const drawn = (seen && !REDUCED()) || REDUCED();
  return (
    <div ref={ref} style={{ display: 'flex', alignItems: 'flex-end', gap: 3, height, width: '100%' }}>
      {data.map((d, i) => {
        const h = (d.count / max) * 100;
        return (
          <div key={i} title={`dia ${d.label}: ${d.count}`} style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', height: '100%' }}>
            <div style={{
              height: drawn ? h + '%' : '0%', minHeight: 3, borderRadius: 4,
              background: color || 'var(--coral)',
              transition: 'height 600ms cubic-bezier(0.22,1,0.36,1)', transitionDelay: (i * 18) + 'ms',
            }} />
          </div>
        );
      })}
    </div>
  );
}

/* ---------------- Single-series area trend (revenue / generic) ---------------- */
function AreaTrend({ data, height = 200, color = '#E14E2E', fmt }) {
  const [ref, seen] = useInView();
  const [hover, setHover] = useState(null);
  const W = 720, H = height, padX = 8, padY = 22;
  const max = Math.max(...data.map((d) => d.cents), 1);
  const x = (i) => padX + (i / (data.length - 1)) * (W - padX * 2);
  const y = (c) => H - padY - (c / max) * (H - padY * 2);
  const line = data.map((d, i) => `${i === 0 ? 'M' : 'L'} ${x(i).toFixed(1)} ${y(d.cents).toFixed(1)}`).join(' ');
  const area = `${line} L ${x(data.length - 1)} ${H - padY} L ${x(0)} ${H - padY} Z`;
  const drawn = (seen && !REDUCED()) || REDUCED();
  return (
    <div ref={ref} style={{ position: 'relative', width: '100%' }}>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} preserveAspectRatio="none"
        onMouseLeave={() => setHover(null)}
        onMouseMove={(e) => { const r = e.currentTarget.getBoundingClientRect(); const rel = ((e.clientX - r.left) / r.width) * W; let idx = Math.round(((rel - padX) / (W - padX * 2)) * (data.length - 1)); setHover(Math.max(0, Math.min(data.length - 1, idx))); }}>
        <defs><linearGradient id="atFill" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor={color} stopOpacity="0.20" /><stop offset="100%" stopColor={color} stopOpacity="0" /></linearGradient></defs>
        {[0.25, 0.5, 0.75].map((g) => <line key={g} x1={padX} x2={W - padX} y1={padY + g * (H - padY * 2)} y2={padY + g * (H - padY * 2)} stroke="var(--line)" strokeWidth="1" strokeDasharray="3 4" />)}
        <path d={area} fill="url(#atFill)" style={{ opacity: drawn ? 1 : 0, transition: 'opacity 600ms ease 300ms' }} />
        <path d={line} fill="none" stroke={color} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" strokeDasharray="2200" strokeDashoffset={drawn ? 0 : 2200} style={{ transition: 'stroke-dashoffset 1100ms cubic-bezier(0.22,1,0.36,1)' }} />
        {hover != null && <g><line x1={x(hover)} x2={x(hover)} y1={padY} y2={H - padY} stroke={color} strokeWidth="1" strokeDasharray="3 3" /><circle cx={x(hover)} cy={y(data[hover].cents)} r="5" fill={color} stroke="#fff" strokeWidth="2" /></g>}
      </svg>
      {hover != null && <div style={{ position: 'absolute', top: 0, left: `${(x(hover) / W) * 100}%`, transform: 'translateX(-50%)', background: 'var(--ink)', color: '#fff', padding: '6px 10px', borderRadius: 10, fontSize: 11, whiteSpace: 'nowrap', pointerEvents: 'none' }}><b>{data[hover].label}</b> · {fmt ? fmt(data[hover].cents) : data[hover].cents}</div>}
      <div className="row between" style={{ fontSize: 11, color: 'var(--subtle)', marginTop: 4 }}>{data.map((d, i) => <span key={i}>{d.label}</span>)}</div>
    </div>
  );
}

/* ---------------- Calendar heatmap (gastos por dia) ---------------- */
function CalHeatmap({ data, fmt }) {
  const [ref, seen] = useInView();
  const max = Math.max(...data.map((d) => d.cents), 1);
  // group into weeks (columns), 7 rows (dow)
  const weeks = [];
  let cur = null;
  data.forEach((d, i) => {
    if (i === 0 || d.dow === 0) { cur = []; weeks.push(cur); }
    cur.push(d);
  });
  const color = (c) => {
    if (c === 0) return 'var(--surface-warm)';
    const t = c / max;
    if (t < 0.25) return 'color-mix(in srgb, var(--coral) 25%, white)';
    if (t < 0.5) return 'color-mix(in srgb, var(--coral) 50%, white)';
    if (t < 0.75) return 'color-mix(in srgb, var(--coral) 75%, white)';
    return 'var(--coral-strong)';
  };
  return (
    <div ref={ref}>
      <div style={{ display: 'flex', gap: 4, overflowX: 'auto', paddingBottom: 4 }}>
        {weeks.map((w, wi) => (
          <div key={wi} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
            {Array.from({ length: 7 }).map((_, dow) => {
              const cell = w.find((x) => x.dow === dow);
              if (!cell) return <div key={dow} style={{ width: 15, height: 15 }} />;
              const idx = wi * 7 + dow;
              return <div key={dow} title={`${cell.date.toLocaleDateString('pt-BR')}: ${fmt ? fmt(cell.cents) : cell.cents}`}
                style={{ width: 15, height: 15, borderRadius: 4, background: seen ? color(cell.cents) : 'var(--surface-warm)', transition: 'background 500ms ease', transitionDelay: (idx * 6) + 'ms' }} />;
            })}
          </div>
        ))}
      </div>
      <div className="row" style={{ gap: 6, justifyContent: 'flex-end', marginTop: 10, fontSize: 11, color: 'var(--subtle)' }}>
        menos
        {['var(--surface-warm)', 'color-mix(in srgb, var(--coral) 25%, white)', 'color-mix(in srgb, var(--coral) 50%, white)', 'color-mix(in srgb, var(--coral) 75%, white)', 'var(--coral-strong)'].map((c, i) => <span key={i} style={{ width: 12, height: 12, borderRadius: 3, background: c }} />)}
        mais
      </div>
    </div>
  );
}

/* ---------------- Multi-series line (categoria no tempo) ---------------- */
function MultiLine({ months, series, height = 220, fmt }) {
  const [ref, seen] = useInView();
  const [hover, setHover] = useState(null);
  const W = 720, H = height, padX = 8, padY = 22;
  const all = series.flatMap((s) => s.values);
  const max = Math.max(...all, 1);
  const x = (i) => padX + (i / (months.length - 1)) * (W - padX * 2);
  const y = (c) => H - padY - (c / max) * (H - padY * 2);
  const drawn = (seen && !REDUCED()) || REDUCED();
  return (
    <div ref={ref}>
      <div className="row wrap" style={{ gap: 14, marginBottom: 12 }}>
        {series.map((s, i) => <span key={s.key} className="row" style={{ gap: 6, fontSize: 12 }}><span style={{ width: 12, height: 3, borderRadius: 2, background: CHART_COLORS[i % CHART_COLORS.length] }} />{s.emoji} {s.name}</span>)}
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} preserveAspectRatio="none"
        onMouseLeave={() => setHover(null)}
        onMouseMove={(e) => { const r = e.currentTarget.getBoundingClientRect(); const rel = ((e.clientX - r.left) / r.width) * W; let idx = Math.round(((rel - padX) / (W - padX * 2)) * (months.length - 1)); setHover(Math.max(0, Math.min(months.length - 1, idx))); }}>
        {[0.25, 0.5, 0.75].map((g) => <line key={g} x1={padX} x2={W - padX} y1={padY + g * (H - padY * 2)} y2={padY + g * (H - padY * 2)} stroke="var(--line)" strokeWidth="1" strokeDasharray="3 4" />)}
        {series.map((s, si) => {
          const path = s.values.map((v, i) => `${i === 0 ? 'M' : 'L'} ${x(i).toFixed(1)} ${y(v).toFixed(1)}`).join(' ');
          return <path key={s.key} d={path} fill="none" stroke={CHART_COLORS[si % CHART_COLORS.length]} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" strokeDasharray="2000" strokeDashoffset={drawn ? 0 : 2000} style={{ transition: 'stroke-dashoffset 1100ms cubic-bezier(0.22,1,0.36,1)', transitionDelay: (si * 120) + 'ms' }} />;
        })}
        {hover != null && <line x1={x(hover)} x2={x(hover)} y1={padY} y2={H - padY} stroke="var(--subtle)" strokeWidth="1" strokeDasharray="3 3" />}
        {hover != null && series.map((s, si) => <circle key={si} cx={x(hover)} cy={y(s.values[hover])} r="4" fill={CHART_COLORS[si % CHART_COLORS.length]} stroke="#fff" strokeWidth="2" />)}
      </svg>
      <div className="row between" style={{ fontSize: 11, color: 'var(--subtle)', marginTop: 4 }}>{months.map((m, i) => <span key={i}>{m}</span>)}</div>
    </div>
  );
}

Object.assign(window, { BarsByCategory, DonutByMethod, TrendLine, CardGauge, Sparkline, VBars, AreaTrend, CalHeatmap, MultiLine, CHART_COLORS });
