// LOLA Consola Web — Gráficas SVG (área, barras, dona, funnel, hbars, sparkline)
// Sin librerías. Marca: navy #1D57A9, accent #F4C71E, success #1F8A5B.
// Exporta a window: AreaChart, BarChart, DonutChart, HBars, Funnel, Sparkline, useHover

const WC = {
  brand: '#1D57A9', brandHi: '#2E6EC4', accent: '#F4C71E', accentDk: '#C99F00',
  success: '#1F8A5B', danger: '#C0392B', warn: '#D98A0B', purple: '#7A5AF8', teal: '#0E9CA6',
  text: '#16202B', sec: '#5B6470', ter: '#8A929E', grid: '#ECEEF1', border: '#E4E7EC',
  mono: "'Geist Mono',ui-monospace,monospace", font: "'Geist',system-ui,sans-serif",
};

const fmtQ = (n, dec = 0) => 'Q' + Number(n).toLocaleString('es-GT', { minimumFractionDigits: dec, maximumFractionDigits: dec });
const fmtK = (n) => {
  if (Math.abs(n) >= 1e6) return 'Q' + (n / 1e6).toFixed(2) + 'M';
  if (Math.abs(n) >= 1e3) return 'Q' + (n / 1e3).toFixed(1) + 'K';
  return 'Q' + n;
};
const fmtN = (n) => Number(n).toLocaleString('es-GT');

// Tooltip flotante simple (compartido)
function useTooltip() {
  const [tip, setTip] = React.useState(null); // {x,y,html}
  const node = tip ? (
    <div style={{ position: 'fixed', left: tip.x, top: tip.y, transform: 'translate(-50%,-115%)',
      background: '#0C1826', color: '#fff', padding: '8px 11px', borderRadius: 9, pointerEvents: 'none',
      fontSize: 12, fontFamily: WC.font, zIndex: 90, whiteSpace: 'nowrap',
      boxShadow: '0 10px 30px -8px rgba(0,0,0,.5)', lineHeight: 1.4 }}>
      {tip.html}
    </div>
  ) : null;
  return [node, setTip];
}

// ── Área / línea con grilla ───────────────────────────────────────────────
function AreaChart({ data, w = 720, h = 240, color = WC.brand, fill = true, fmt = fmtK, labelEvery = 1, pad = 34 }) {
  const [tip, setTip] = useTooltip();
  const max = Math.max(...data.map(d => d.v)) * 1.12 || 1;
  const min = 0;
  const iw = w - pad * 2, ih = h - pad * 1.4;
  const x = (i) => pad + (i / (data.length - 1)) * iw;
  const y = (v) => pad * 0.4 + ih - ((v - min) / (max - min)) * ih;
  const pts = data.map((d, i) => [x(i), y(d.v)]);
  const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  const area = line + ` L${x(data.length - 1).toFixed(1)} ${(pad * 0.4 + ih).toFixed(1)} L${x(0).toFixed(1)} ${(pad * 0.4 + ih).toFixed(1)} Z`;
  const ticks = 4;
  const gid = 'g' + color.replace('#', '');

  return (
    <div style={{ position: 'relative', width: '100%' }}>
      {tip}
      <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: 'block', fontFamily: WC.font }}>
        <defs>
          <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.22"/>
            <stop offset="100%" stopColor={color} stopOpacity="0"/>
          </linearGradient>
        </defs>
        {Array.from({ length: ticks + 1 }).map((_, i) => {
          const gy = pad * 0.4 + (ih / ticks) * i;
          const val = max - (max - min) * (i / ticks);
          return (
            <g key={i}>
              <line x1={pad} y1={gy} x2={w - pad} y2={gy} stroke={WC.grid} strokeWidth="1"/>
              <text x={pad - 8} y={gy + 3.5} textAnchor="end" fontSize="10" fill={WC.ter} fontFamily={WC.mono}>{fmt(val)}</text>
            </g>
          );
        })}
        {fill && <path d={area} fill={`url(#${gid})`}/>}
        <path d={line} fill="none" stroke={color} strokeWidth="2.4" strokeLinejoin="round" strokeLinecap="round"/>
        {pts.map((p, i) => (
          <g key={i}>
            <circle cx={p[0]} cy={p[1]} r="9" fill="transparent"
              onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, html: <span><b>{fmt(data[i].v)}</b> · {data[i].l}</span> })}
              onMouseLeave={() => setTip(null)} style={{ cursor: 'pointer' }}/>
            <circle cx={p[0]} cy={p[1]} r="2.6" fill={color} stroke="#fff" strokeWidth="1.4" style={{ pointerEvents: 'none' }}/>
          </g>
        ))}
        {data.map((d, i) => (i % labelEvery === 0 || i === data.length - 1) ? (
          <text key={i} x={x(i)} y={h - 6} textAnchor="middle" fontSize="9.5" fill={WC.ter} fontFamily={WC.mono}>{d.l}</text>
        ) : null)}
      </svg>
    </div>
  );
}

// ── Barras verticales (con opción comparativa) ─────────────────────────────
function BarChart({ data, w = 720, h = 240, color = WC.brand, color2 = WC.accent, fmt = fmtK, pad = 34, stacked = false }) {
  const [tip, setTip] = useTooltip();
  const has2 = data.some(d => d.v2 != null);
  const max = Math.max(...data.map(d => stacked && has2 ? d.v + (d.v2 || 0) : Math.max(d.v, d.v2 || 0))) * 1.14 || 1;
  const iw = w - pad * 2, ih = h - pad * 1.4;
  const n = data.length;
  const slot = iw / n;
  const bw = has2 && !stacked ? slot * 0.3 : slot * 0.5;
  const y0 = pad * 0.4 + ih;
  const ticks = 4;
  return (
    <div style={{ position: 'relative', width: '100%' }}>
      {tip}
      <svg viewBox={`0 0 ${w} ${h}`} width="100%" style={{ display: 'block', fontFamily: WC.font }}>
        {Array.from({ length: ticks + 1 }).map((_, i) => {
          const gy = pad * 0.4 + (ih / ticks) * i;
          const val = max - max * (i / ticks);
          return (
            <g key={i}>
              <line x1={pad} y1={gy} x2={w - pad} y2={gy} stroke={WC.grid} strokeWidth="1"/>
              <text x={pad - 8} y={gy + 3.5} textAnchor="end" fontSize="10" fill={WC.ter} fontFamily={WC.mono}>{fmt(val)}</text>
            </g>
          );
        })}
        {data.map((d, i) => {
          const cx = pad + slot * i + slot / 2;
          const bh = (d.v / max) * ih;
          const bh2 = ((d.v2 || 0) / max) * ih;
          if (stacked && has2) {
            return (
              <g key={i}>
                <rect x={cx - bw / 2} y={y0 - bh} width={bw} height={bh} rx="3" fill={color}
                  onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, html: <span>{d.l}: <b>{fmt(d.v)}</b></span> })} onMouseLeave={() => setTip(null)}/>
                <rect x={cx - bw / 2} y={y0 - bh - bh2} width={bw} height={bh2} rx="3" fill={color2}
                  onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, html: <span>{d.l}: <b>{fmt(d.v2)}</b></span> })} onMouseLeave={() => setTip(null)}/>
                <text x={cx} y={h - 6} textAnchor="middle" fontSize="9.5" fill={WC.ter} fontFamily={WC.mono}>{d.l}</text>
              </g>
            );
          }
          return (
            <g key={i}>
              <rect x={has2 ? cx - bw - 2 : cx - bw / 2} y={y0 - bh} width={bw} height={bh} rx="3" fill={color}
                onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, html: <span>{d.l}: <b>{fmt(d.v)}</b></span> })} onMouseLeave={() => setTip(null)}
                style={{ cursor: 'pointer' }}/>
              {has2 && <rect x={cx + 2} y={y0 - bh2} width={bw} height={bh2} rx="3" fill={color2}
                onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, html: <span>{d.l}: <b>{fmt(d.v2)}</b></span> })} onMouseLeave={() => setTip(null)}
                style={{ cursor: 'pointer' }}/>}
              <text x={cx} y={h - 6} textAnchor="middle" fontSize="9.5" fill={WC.ter} fontFamily={WC.mono}>{d.l}</text>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

// ── Dona ────────────────────────────────────────────────────────────────
function DonutChart({ data, size = 200, thickness = 26, fmt = fmtN, center }) {
  const [tip, setTip] = useTooltip();
  const total = data.reduce((s, d) => s + d.v, 0) || 1;
  const r = (size - thickness) / 2;
  const cx = size / 2, cy = size / 2;
  const C = 2 * Math.PI * r;
  let acc = 0;
  return (
    <div style={{ position: 'relative', display: 'flex', alignItems: 'center', gap: 18 }}>
      {tip}
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)', flexShrink: 0 }}>
        <circle cx={cx} cy={cy} r={r} fill="none" stroke={WC.grid} strokeWidth={thickness}/>
        {data.map((d, i) => {
          const frac = d.v / total;
          const dash = frac * C;
          const off = acc * C;
          acc += frac;
          return (
            <circle key={i} cx={cx} cy={cy} r={r} fill="none" stroke={d.c} strokeWidth={thickness}
              strokeDasharray={`${dash} ${C - dash}`} strokeDashoffset={-off} strokeLinecap="butt"
              onMouseEnter={(e) => setTip({ x: e.clientX, y: e.clientY, html: <span>{d.l}: <b>{fmt(d.v)}</b> ({Math.round(frac * 100)}%)</span> })}
              onMouseLeave={() => setTip(null)} style={{ cursor: 'pointer', transition: 'opacity .15s' }}/>
          );
        })}
      </svg>
      {center && (
        <div style={{ position: 'absolute', left: size / 2, top: size / 2, transform: 'translate(-50%,-50%)',
          textAlign: 'center', pointerEvents: 'none' }}>
          <div style={{ fontSize: 22, fontWeight: 800, color: WC.text, fontFamily: WC.mono, letterSpacing: -.5 }}>{center.big}</div>
          <div style={{ fontSize: 10.5, color: WC.ter, fontFamily: WC.mono, textTransform: 'uppercase', letterSpacing: 1 }}>{center.small}</div>
        </div>
      )}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 9, minWidth: 0 }}>
        {data.map((d, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 9, fontSize: 13 }}>
            <span style={{ width: 11, height: 11, borderRadius: 3, background: d.c, flexShrink: 0 }}/>
            <span style={{ color: WC.sec, flex: 1 }}>{d.l}</span>
            <span style={{ fontWeight: 700, fontFamily: WC.mono, color: WC.text }}>{Math.round(d.v / total * 100)}%</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── Barras horizontales (ranking) ─────────────────────────────────────────
function HBars({ data, fmt = fmtK, color = WC.brand, maxRows = 6 }) {
  const max = Math.max(...data.map(d => d.v)) || 1;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 13 }}>
      {data.slice(0, maxRows).map((d, i) => (
        <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ width: 26, fontFamily: WC.mono, fontSize: 12, color: WC.ter, fontWeight: 700, flexShrink: 0 }}>{String(i + 1).padStart(2, '0')}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 5 }}>
              <span style={{ fontSize: 13, fontWeight: 600, color: WC.text, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.l}</span>
              <span style={{ fontSize: 12.5, fontWeight: 700, fontFamily: WC.mono, color: WC.text, marginLeft: 10, flexShrink: 0 }}>{fmt(d.v)}</span>
            </div>
            <div style={{ height: 8, background: WC.grid, borderRadius: 5, overflow: 'hidden' }}>
              <div style={{ width: (d.v / max * 100) + '%', height: '100%', background: d.c || color, borderRadius: 5,
                transition: 'width .5s cubic-bezier(.3,1,.4,1)' }}/>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

// ── Funnel ────────────────────────────────────────────────────────────────
function Funnel({ data }) {
  const max = data[0].v || 1;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {data.map((d, i) => {
        const pct = d.v / max;
        const conv = i === 0 ? 100 : Math.round(d.v / data[i - 1].v * 100);
        return (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <div style={{ width: 130, flexShrink: 0 }}>
              <div style={{ fontSize: 13, fontWeight: 600, color: WC.text }}>{d.l}</div>
              <div style={{ fontSize: 11, color: WC.ter, fontFamily: WC.mono }}>{fmtN(d.v)}</div>
            </div>
            <div style={{ flex: 1, height: 34, background: WC.grid, borderRadius: 7, overflow: 'hidden', position: 'relative' }}>
              <div style={{ width: (pct * 100) + '%', height: '100%', background: `linear-gradient(90deg, ${WC.brand}, ${WC.brandHi})`,
                borderRadius: 7, display: 'flex', alignItems: 'center', paddingLeft: 12, transition: 'width .6s cubic-bezier(.3,1,.4,1)' }}>
                <span style={{ fontSize: 12, fontWeight: 700, color: '#fff', fontFamily: WC.mono }}>{Math.round(pct * 100)}%</span>
              </div>
            </div>
            <div style={{ width: 54, flexShrink: 0, textAlign: 'right' }}>
              {i > 0 && <span style={{ fontSize: 12, fontWeight: 700, fontFamily: WC.mono,
                color: conv >= 60 ? WC.success : conv >= 35 ? WC.warn : WC.danger }}>{conv}%</span>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ── Sparkline mini ─────────────────────────────────────────────────────────
function Sparkline({ data, w = 110, h = 34, color = WC.brand, up = true }) {
  const max = Math.max(...data), min = Math.min(...data);
  const rng = max - min || 1;
  const pts = data.map((v, i) => [(i / (data.length - 1)) * w, h - ((v - min) / rng) * (h - 4) - 2]);
  const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  const c = up ? WC.success : WC.danger;
  return (
    <svg width={w} height={h} style={{ display: 'block' }}>
      <path d={`${line} L${w} ${h} L0 ${h} Z`} fill={c} opacity="0.1"/>
      <path d={line} fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

Object.assign(window, { WC, fmtQ, fmtK, fmtN, AreaChart, BarChart, DonutChart, HBars, Funnel, Sparkline });
