// Primitivos de gráfica: Sparkline, LineChart, StackedBar, DonutChart, RatingBars, Heatmap.
// SVG puro + hover tooltips. Colores siempre desde DS tokens.

const fmt = (n, opts = {}) => {
  if (n == null) return "—";
  if (opts.k && Math.abs(n) >= 1000) return (n / 1000).toFixed(1).replace(".", ",") + "k";
  return Math.round(n).toLocaleString("es-ES");
};
const fmtDec = (n, d = 1) => n.toFixed(d).replace(".", ",");
const fmtPct = (n) => (n >= 0 ? "+" : "") + fmtDec(n, 1) + "%";

// Sparkline: pequeña tendencia sin ejes. Rellena de gradiente sutil.
const Sparkline = ({ data, w = 160, h = 44, color = "var(--brand-blue)", fill = true, accent }) => {
  const pad = 5; // margen interior para que el dot y el stroke no se corten
  const min = Math.min(...data);
  const max = Math.max(...data);
  const span = Math.max(0.001, max - min);
  const px = (i) => (i / (data.length - 1)) * w;
  const py = (v) => h - ((v - min) / span) * (h - pad * 2) - pad;
  const path = data.map((v, i) => `${i === 0 ? "M" : "L"}${px(i).toFixed(1)},${py(v).toFixed(1)}`).join(" ");
  const area = path + ` L${w},${h} L0,${h} Z`;
  const gid = "spark_" + Math.random().toString(36).slice(2, 7);
  const clipId = "clip_" + gid;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width={w} height={h} preserveAspectRatio="none"
         style={{ display: "block", overflow: "hidden" }}>
      <defs>
        <clipPath id={clipId}>
          <rect x="0" y="0" width={w} height={h} />
        </clipPath>
        {fill && (
          <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor={color} stopOpacity=".22" />
            <stop offset="1" stopColor={color} stopOpacity="0" />
          </linearGradient>
        )}
      </defs>
      <g clipPath={`url(#${clipId})`}>
        {fill && <path d={area} fill={`url(#${gid})`} />}
        <path d={path} fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
        {accent && data.length > 0 && (
          <circle cx={px(data.length - 1)} cy={py(data[data.length - 1])} r="3" fill={color} />
        )}
      </g>
    </svg>
  );
};

// LineChart: con ejes, dos series posibles, hover crosshair.
const LineChart = ({
  series, // [{ name, color, data: [{x, y}] }]
  height = 220,
  yDomain, // [min, max] override
  yTicks = 4,
  yFormat = (v) => fmt(v, { k: true }),
  xLabel = (d) => d.x,
  showLegend = true,
  axisFontSize = 10,
  legendFontSize = 11,
  padding,
}) => {
  const padL = padding?.l ?? 44, padR = padding?.r ?? 16, padT = padding?.t ?? 14, padB = padding?.b ?? 28;
  const [hover, setHover] = React.useState(null);
  const wrapRef = React.useRef(null);
  const [w, setW] = React.useState(800);
  React.useEffect(() => {
    if (!wrapRef.current) return;
    const ro = new ResizeObserver(([e]) => setW(e.contentRect.width));
    ro.observe(wrapRef.current);
    return () => ro.disconnect();
  }, []);

  const n = series[0].data.length;
  const allY = series.flatMap(s => s.data.map(d => d.y));
  const minY = yDomain ? yDomain[0] : Math.min(...allY);
  const maxY = yDomain ? yDomain[1] : Math.max(...allY);
  const spanY = Math.max(0.001, maxY - minY);
  const innerW = Math.max(0, w - padL - padR);
  const innerH = height - padT - padB;
  const px = (i) => padL + (i / Math.max(1, n - 1)) * innerW;
  const py = (v) => padT + innerH - ((v - minY) / spanY) * innerH;

  const ticks = Array.from({ length: yTicks + 1 }, (_, i) => minY + (spanY * i) / yTicks);

  return (
    <div ref={wrapRef} style={{ width: "100%" }}>
      <svg viewBox={`0 0 ${w} ${height}`} width="100%" height={height} style={{ display: "block", overflow: "visible" }}>
        {/* Grid */}
        {ticks.map((t, i) => (
          <g key={i}>
            <line x1={padL} x2={w - padR} y1={py(t)} y2={py(t)} stroke="var(--grey-200)" strokeWidth="1" />
            <text x={padL - 8} y={py(t)} textAnchor="end" dominantBaseline="central"
                  style={{ fontSize: axisFontSize, fill: "var(--grey-700)", fontFamily: "var(--font-num)", fontWeight: 500 }}>
              {yFormat(t)}
            </text>
          </g>
        ))}

        {/* X labels (sparse) */}
        {series[0].data.map((d, i) => {
          const showEvery = Math.max(1, Math.round(n / 8));
          if (i % showEvery !== 0 && i !== n - 1) return null;
          return (
            <text key={i} x={px(i)} y={height - 8} textAnchor="middle"
                  style={{ fontSize: axisFontSize, fill: "var(--grey-700)", fontWeight: 500 }}>
              {xLabel(d)}
            </text>
          );
        })}

        {/* Lines */}
        {series.map((s) => {
          const path = s.data.map((d, i) => `${i === 0 ? "M" : "L"}${px(i).toFixed(1)},${py(d.y).toFixed(1)}`).join(" ");
          return (
            <g key={s.name}>
              <path d={path} fill="none" stroke={s.color} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
              {s.data.map((d, i) => (
                <circle key={i} cx={px(i)} cy={py(d.y)} r={hover === i ? 4 : 2.5} fill={s.color} />
              ))}
            </g>
          );
        })}

        {/* Hover crosshair */}
        {hover != null && (
          <g>
            <line x1={px(hover)} x2={px(hover)} y1={padT} y2={padT + innerH}
                  stroke="var(--grey-700)" strokeDasharray="2 3" strokeWidth="1" />
          </g>
        )}

        {/* Hit areas */}
        {series[0].data.map((d, i) => (
          <rect key={i} x={px(i) - (innerW / (n - 1)) / 2} y={padT}
                width={innerW / Math.max(1, n - 1)} height={innerH}
                fill="transparent"
                onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)} />
        ))}
      </svg>

      {/* Tooltip below */}
      <div style={{ minHeight: 36, marginTop: 6, display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
        {showLegend && series.map(s => (
          <span key={s.name} style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: legendFontSize, color: "var(--grey-700)", fontWeight: 700 }}>
            <span style={{ width: 10, height: 2, background: s.color, borderRadius: 1 }} />
            {s.name}
            {hover != null && (
              <span style={{ marginLeft: 6, color: "#000", fontFamily: "var(--font-num)", fontVariantNumeric: "tabular-nums" }}>
                {yFormat(s.data[hover].y)}
              </span>
            )}
          </span>
        ))}
        {hover != null && (
          <span style={{ fontSize: legendFontSize, color: "var(--grey-700)", marginLeft: "auto", fontFamily: "var(--font-num)" }}>
            {xLabel(series[0].data[hover])}
          </span>
        )}
      </div>
    </div>
  );
};

// StackedBar: barras apiladas (iOS + Android por semana).
const StackedBar = ({ data, height = 220, colors = { ios: "var(--chart-3)", android: "var(--chart-1)" }, yFormat = (v) => fmt(v, { k: true }) }) => {
  const padL = 44, padR = 16, padT = 14, padB = 28;
  const wrapRef = React.useRef(null);
  const [w, setW] = React.useState(800);
  const [hover, setHover] = React.useState(null);
  React.useEffect(() => {
    if (!wrapRef.current) return;
    const ro = new ResizeObserver(([e]) => setW(e.contentRect.width));
    ro.observe(wrapRef.current);
    return () => ro.disconnect();
  }, []);

  const totals = data.map(d => d.ios + d.android);
  const maxY = Math.max(...totals) * 1.1;
  const innerW = Math.max(0, w - padL - padR);
  const innerH = height - padT - padB;
  const bw = (innerW / data.length) * 0.55;
  const step = innerW / data.length;
  const cx = (i) => padL + step * i + step / 2;
  const yScale = (v) => (v / maxY) * innerH;
  const ticks = 4;

  return (
    <div ref={wrapRef} style={{ width: "100%" }}>
      <svg viewBox={`0 0 ${w} ${height}`} width="100%" height={height} style={{ display: "block", overflow: "visible" }}>
        {Array.from({ length: ticks + 1 }).map((_, i) => {
          const v = (maxY * i) / ticks;
          const y = padT + innerH - yScale(v);
          return (
            <g key={i}>
              <line x1={padL} x2={w - padR} y1={y} y2={y} stroke="var(--grey-200)" strokeWidth="1" />
              <text x={padL - 8} y={y} textAnchor="end" dominantBaseline="central"
                    style={{ fontSize: 10, fill: "var(--grey-700)", fontFamily: "var(--font-num)" }}>
                {yFormat(v)}
              </text>
            </g>
          );
        })}
        {data.map((d, i) => {
          const total = d.ios + d.android;
          const hIos = yScale(d.ios);
          const hAnd = yScale(d.android);
          const y0 = padT + innerH;
          const isHover = hover === i;
          return (
            <g key={i}>
              <rect x={cx(i) - bw / 2} y={y0 - hAnd} width={bw} height={hAnd}
                    fill={colors.android} opacity={hover != null && !isHover ? 0.45 : 1} rx="2" />
              <rect x={cx(i) - bw / 2} y={y0 - hAnd - hIos} width={bw} height={hIos}
                    fill={colors.ios} opacity={hover != null && !isHover ? 0.45 : 1} rx="2" />
              {isHover && (
                <g>
                  <text x={cx(i)} y={y0 - hAnd - hIos - 6} textAnchor="middle"
                        style={{ fontSize: 11, fill: "#000", fontWeight: 800, fontFamily: "var(--font-num)" }}>
                    {fmt(total, { k: true })}
                  </text>
                </g>
              )}
              <text x={cx(i)} y={height - 8} textAnchor="middle"
                    style={{ fontSize: 10, fill: "var(--grey-700)" }}>
                {d.w}
              </text>
              <rect x={cx(i) - step / 2} y={padT} width={step} height={innerH}
                    fill="transparent" onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)} />
            </g>
          );
        })}
      </svg>
    </div>
  );
};

// DonutChart: dos segmentos (iOS, Android) con etiquetas.
const DonutChart = ({ ios, android, size = 180, colors = { ios: "var(--chart-3)", android: "var(--chart-1)" }, slideMode = false }) => {
  const total = ios + android;
  const r = size / 2 - 14;
  const cx = size / 2, cy = size / 2;
  const stroke = slideMode ? 30 : 22;
  const C = 2 * Math.PI * r;
  const fIos = ios / total;
  const fAnd = android / total;
  const totalSize = slideMode ? 36 : 22;
  const labelSize = slideMode ? 16 : 10;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: slideMode ? 36 : 20 }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--grey-100)" strokeWidth={stroke} />
        <circle cx={cx} cy={cy} r={r} fill="none" stroke={colors.android} strokeWidth={stroke}
                strokeDasharray={`${C * fAnd} ${C}`} transform={`rotate(-90 ${cx} ${cy})`} strokeLinecap="butt" />
        <circle cx={cx} cy={cy} r={r} fill="none" stroke={colors.ios} strokeWidth={stroke}
                strokeDasharray={`${C * fIos} ${C}`} strokeDashoffset={`-${C * fAnd}`}
                transform={`rotate(-90 ${cx} ${cy})`} strokeLinecap="butt" />
        <text x={cx} y={cy - (slideMode ? 6 : 4)} textAnchor="middle"
              style={{ fontSize: totalSize, fontWeight: 900, fill: "#000", fontFamily: "var(--font-num)" }}>
          {fmt(total, { k: true })}
        </text>
        <text x={cx} y={cy + (slideMode ? 22 : 14)} textAnchor="middle"
              style={{ fontSize: labelSize, fill: "var(--grey-700)", textTransform: "uppercase", letterSpacing: ".12em", fontWeight: 700 }}>
          Total
        </text>
      </svg>
      <div style={{ display: "flex", flexDirection: "column", gap: slideMode ? 14 : 10, fontSize: slideMode ? 22 : 12 }}>
        <DonutLegendRow color={colors.ios} label="iOS" pct={Math.round(fIos * 100)} val={ios} slideMode={slideMode} />
        <DonutLegendRow color={colors.android} label="Android" pct={Math.round(fAnd * 100)} val={android} slideMode={slideMode} />
      </div>
    </div>
  );
};

const DonutLegendRow = ({ color, label, pct, val, slideMode }) => (
  <div style={{ display: "flex", alignItems: "baseline", gap: slideMode ? 10 : 8 }}>
    <span style={{ width: slideMode ? 14 : 8, height: slideMode ? 14 : 8, background: color, borderRadius: slideMode ? 3 : 2, display: "inline-block", alignSelf: "center" }} />
    <span style={{ fontWeight: 800, color: "#000", minWidth: slideMode ? 100 : 56, fontSize: slideMode ? 22 : 12 }}>{label}</span>
    <span style={{ fontFamily: "var(--font-num)", fontWeight: 900, fontSize: slideMode ? 32 : 14, color: "#000" }}>{pct}%</span>
    <span style={{ color: "var(--grey-700)", fontSize: slideMode ? 22 : 11, fontFamily: "var(--font-num)", fontWeight: 500 }}>· {fmt(val)}</span>
  </div>
);

// RatingBars: distribución de estrellas (5 → 1) en barras horizontales.
const RatingBars = ({ stars }) => {
  const order = [5, 4, 3, 2, 1];
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
      {order.map((k) => {
        const v = stars[k] || 0;
        const tone = k >= 4 ? "var(--pos-600)" : k === 3 ? "var(--grey-700)" : "var(--neg-600)";
        return (
          <div key={k} style={{ display: "grid", gridTemplateColumns: "16px 1fr 32px", alignItems: "center", gap: 8 }}>
            <span style={{ fontSize: 11, fontWeight: 800, color: "var(--grey-700)", fontFamily: "var(--font-num)" }}>{k}★</span>
            <div style={{ position: "relative", height: 6, background: "var(--grey-100)", borderRadius: 3, overflow: "hidden" }}>
              <div style={{ position: "absolute", inset: 0, width: `${v}%`, background: tone, borderRadius: 3 }} />
            </div>
            <span style={{ fontSize: 11, color: "#000", textAlign: "right", fontFamily: "var(--font-num)", fontWeight: 700 }}>{v}%</span>
          </div>
        );
      })}
    </div>
  );
};

// Heatmap: filas = categorías, columnas = semanas, intensidad = nº menciones.
const Heatmap = ({ rows, weekLabels }) => {
  const allVals = rows.flatMap(r => r.weeks);
  const max = Math.max(...allVals);
  const tone = (v) => {
    const t = v / max;
    // ramp blanco → azul de marca
    const lightness = 96 - t * 60;
    return `hsl(220 100% ${lightness}%)`;
  };
  return (
    <div style={{ display: "grid", gridTemplateColumns: `160px repeat(${weekLabels.length}, 1fr)`, gap: 2 }}>
      <div />
      {weekLabels.map((w, i) => (
        <div key={i} style={{ textAlign: "center", fontSize: 10, fontWeight: 800, color: "var(--grey-700)", letterSpacing: ".06em", textTransform: "uppercase", paddingBottom: 4 }}>{w}</div>
      ))}
      {rows.map((r, ri) => (
        <React.Fragment key={r.name}>
          <div style={{ fontSize: 12, fontWeight: 700, color: "#000", display: "flex", alignItems: "center", paddingRight: 8 }}>{r.name}</div>
          {r.weeks.map((v, wi) => (
            <div key={wi} title={`${r.name} · ${weekLabels[wi]}: ${v} menciones`}
                 style={{
                   height: 28,
                   background: tone(v),
                   borderRadius: 4,
                   display: "flex", alignItems: "center", justifyContent: "center",
                   fontSize: 11, fontWeight: 800, fontFamily: "var(--font-num)",
                   color: v / max > 0.55 ? "#fff" : "#000",
                 }}>
              {v}
            </div>
          ))}
        </React.Fragment>
      ))}
    </div>
  );
};

Object.assign(window, { fmt, fmtDec, fmtPct, Sparkline, LineChart, StackedBar, DonutChart, RatingBars, Heatmap });
