/* global React */
const { useState: useStateCh, useEffect: useEffectCh, useMemo: useMemoCh, useRef: useRefCh } = React;

// ===== SubsChart — динамика подписчиков =====
// Одна линия (сумма / конкретная платформа) + чипы-тогглы под графиком.
// Ось X растягивается по всей доступной хронологии (min..max day), чтобы
// график никогда не имел пустого «хвоста» в начале.
function SubsChart({ bloggerId, totalFallback, platforms }) {
  const [rows, setRows] = useStateCh(null); // null=loading, [] = пусто
  const [platform, setPlatform] = useStateCh("all");
  const [hover, setHover] = useStateCh(null); // {idx, x, y, day, value, platform}
  const svgRef = useRefCh(null);

  useEffectCh(() => {
    if (!bloggerId) return;
    let cancelled = false;
    fetch("/api/bloggers/" + encodeURIComponent(bloggerId) + "/history")
      .then(r => r.ok ? r.json() : [])
      .then(d => { if (!cancelled) setRows(Array.isArray(d) ? d : []); })
      .catch(() => { if (!cancelled) setRows([]); });
    return () => { cancelled = true; };
  }, [bloggerId]);

  // Build list of currently active platforms with their raw aliases (admin DB names).
  // Used to (a) gap-fill missing days with current value, (b) detect that a snapshot
  // already covers a platform so we don't double-count it.
  const currentPlatforms = useMemoCh(() => {
    const list = []; // [{ display, subs, rawSet:Set<string> }]
    const aliasToIdx = new Map(); // any alias (lowercased) → index in list
    if (Array.isArray(platforms)) {
      for (const p of platforms) {
        if (!p) continue;
        const subs = Number(p.subs) || 0;
        if (subs <= 0) continue;
        const display = (p.name || '').trim();
        if (!display) continue;
        const rawNames = Array.isArray(p.rawNames) && p.rawNames.length ? p.rawNames : [display];
        const entry = { display, subs, rawSet: new Set(rawNames.map(n => String(n).toLowerCase())) };
        entry.rawSet.add(display.toLowerCase());
        list.push(entry);
        const idx = list.length - 1;
        for (const a of entry.rawSet) aliasToIdx.set(a, idx);
      }
    }
    return { list, aliasToIdx };
  }, [platforms]);

  // Собираем список уникальных дней (отсортированный) и платформ.
  // Чипы показываем по канонічному display-имени (как в карточке профиля).
  const { days, platformsSet } = useMemoCh(() => {
    const daySet = new Set();
    const displayLabels = new Set();
    if (rows && rows.length) {
      for (const r of rows) {
        daySet.add(r.day);
        const idx = currentPlatforms.aliasToIdx.get(String(r.platform).toLowerCase());
        if (idx !== undefined) displayLabels.add(currentPlatforms.list[idx].display);
        else if (r.platform) displayLabels.add(r.platform);
      }
    }
    for (const e of currentPlatforms.list) displayLabels.add(e.display);
    return {
      days: Array.from(daySet).sort(),
      platformsSet: Array.from(displayLabels).sort(),
    };
  }, [rows, currentPlatforms]);

  // series — массив значений по дням для выбранной вкладки.
  // Для активной платформы без снимка на дату подставляем её текущее значение
  // (плоская линия), чтобы сумма совпадала с total_audience в шапке профиля.
  const series = useMemoCh(() => {
    if (!rows || !days.length) return [];
    const byDay = new Map(); // Map<day, Map<aliasLower, subs>>
    for (const r of rows) {
      if (!byDay.has(r.day)) byDay.set(r.day, new Map());
      byDay.get(r.day).set(String(r.platform).toLowerCase(), r.subs);
    }
    return days.map(day => {
      const pmap = byDay.get(day) || new Map();
      let value = 0;
      if (platform === "all") {
        // Sum across active platforms; for each, prefer snapshot value if any of its
        // aliases is present that day, otherwise gap-fill with current subscriber count.
        for (const e of currentPlatforms.list) {
          let snap = null;
          for (const a of e.rawSet) {
            if (pmap.has(a)) { snap = pmap.get(a) || 0; break; }
          }
          value += snap !== null ? snap : (e.subs || 0);
        }
        // Add any historical platforms that are not part of currentPlatforms (e.g.
        // a platform was removed from the profile but its history still exists).
        const usedAliases = new Set();
        for (const e of currentPlatforms.list) for (const a of e.rawSet) usedAliases.add(a);
        for (const [a, v] of pmap) {
          if (!usedAliases.has(a)) value += v || 0;
        }
      } else {
        // platform here is the display label. Resolve to an entry, then look up snapshot
        // by any of its aliases; gap-fill with its current subs.
        const idx = currentPlatforms.aliasToIdx.get(String(platform).toLowerCase());
        const entry = idx !== undefined ? currentPlatforms.list[idx] : null;
        if (entry) {
          let snap = null;
          for (const a of entry.rawSet) {
            if (pmap.has(a)) { snap = pmap.get(a) || 0; break; }
          }
          value = snap !== null ? snap : (entry.subs || 0);
        } else {
          value = pmap.get(String(platform).toLowerCase()) || 0;
        }
      }
      return { day, value };
    });
  }, [rows, days, platform, currentPlatforms]);

  if (rows === null) return <div className="subs-chart subs-chart-empty">Загрузка…</div>;
  if (!rows.length || series.length < 2) {
    return (
      <div className="subs-chart subs-chart-empty">
        <div className="subs-chart-empty-icon" aria-hidden>∿</div>
        <div>
          <div className="subs-chart-empty-title">Недостаточно данных</div>
          <div className="subs-chart-empty-sub">
            График появится после нескольких дней сбора{totalFallback ? ` · сейчас ${window.fmtK(totalFallback)}` : ""}
          </div>
        </div>
      </div>
    );
  }

  // SVG coords
  const W = 560, H = 180, PAD_L = 52, PAD_R = 16, PAD_T = 14, PAD_B = 28;
  const xRange = W - PAD_L - PAD_R;
  const yRange = H - PAD_T - PAD_B;
  const maxY = Math.max(1, ...series.map(p => p.value));
  const minY = 0;

  const x = i => PAD_L + (series.length === 1 ? xRange / 2 : (i * xRange) / (series.length - 1));
  const y = v => PAD_T + yRange - ((v - minY) / (maxY - minY)) * yRange;

  const pointsAttr = series.map((p, i) => x(i) + "," + y(p.value)).join(" ");
  const areaPath =
    "M " + x(0) + " " + (PAD_T + yRange) + " " +
    "L " + series.map((p, i) => x(i) + " " + y(p.value)).join(" L ") + " " +
    "L " + x(series.length - 1) + " " + (PAD_T + yRange) + " Z";

  const firstDay = days[0], lastDay = days[days.length - 1];
  const fmtDate = iso => {
    const d = new Date(iso + "T00:00:00");
    return d.toLocaleDateString("ru-RU", { day: "numeric", month: "short" });
  };
  const fmtYear = iso => new Date(iso + "T00:00:00").getFullYear();

  // Hover: find nearest point to pointer
  const onMove = e => {
    const rect = svgRef.current.getBoundingClientRect();
    const relX = ((e.clientX - rect.left) / rect.width) * W;
    let best = 0, bestDist = Infinity;
    for (let i = 0; i < series.length; i++) {
      const d = Math.abs(x(i) - relX);
      if (d < bestDist) { bestDist = d; best = i; }
    }
    const p = series[best];
    setHover({ idx: best, x: x(best), y: y(p.value), day: p.day, value: p.value });
  };
  const onLeave = () => setHover(null);

  const gradId = "subs-grad-" + (bloggerId || "x");

  return (
    <div className="subs-chart">
      <svg
        ref={svgRef}
        viewBox={"0 0 " + W + " " + H}
        preserveAspectRatio="none"
        onMouseMove={onMove}
        onMouseLeave={onLeave}
      >
        <defs>
          <linearGradient id={gradId} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor="#26d97f" stopOpacity="0.32"/>
            <stop offset="100%" stopColor="#26d97f" stopOpacity="0"/>
          </linearGradient>
        </defs>
        {/* Y grid: 3 тонкие линии */}
        {[0.25, 0.5, 0.75].map(t => {
          const yy = PAD_T + yRange * (1 - t);
          return <line key={t} x1={PAD_L} x2={W - PAD_R} y1={yy} y2={yy} stroke="rgba(255,255,255,0.05)" strokeWidth="1"/>;
        })}
        {/* Y labels */}
        {[0, 0.5, 1].map(t => {
          const yy = PAD_T + yRange * (1 - t);
          const val = minY + (maxY - minY) * t;
          return (
            <text key={t} x={PAD_L - 8} y={yy + 4} textAnchor="end"
                  style={{fontFamily: "var(--mono)", fontSize: 10, fill: "rgba(255,255,255,0.35)"}}>
              {window.fmtK(Math.round(val))}
            </text>
          );
        })}
        {/* Area */}
        <path d={areaPath} fill={"url(#" + gradId + ")"} />
        {/* Line */}
        <polyline points={pointsAttr} fill="none" stroke="#26d97f" strokeWidth="2"
                  strokeLinecap="round" strokeLinejoin="round"/>
        {/* X labels — first and last day only */}
        <text x={PAD_L} y={H - 8}
              style={{fontFamily: "var(--mono)", fontSize: 10, fill: "rgba(255,255,255,0.35)"}}>
          {fmtDate(firstDay)} {fmtYear(firstDay) !== fmtYear(lastDay) ? fmtYear(firstDay) : ""}
        </text>
        <text x={W - PAD_R} y={H - 8} textAnchor="end"
              style={{fontFamily: "var(--mono)", fontSize: 10, fill: "rgba(255,255,255,0.35)"}}>
          {fmtDate(lastDay)} {fmtYear(lastDay)}
        </text>
        {/* Hover */}
        {hover && (
          <g>
            <line x1={hover.x} x2={hover.x} y1={PAD_T} y2={PAD_T + yRange}
                  stroke="rgba(38,217,127,0.45)" strokeWidth="1" strokeDasharray="3 3"/>
            <circle cx={hover.x} cy={hover.y} r="4" fill="#26d97f"/>
          </g>
        )}
      </svg>
      {hover && (
        <div className="subs-chart-tip"
             style={{ left: (hover.x / W) * 100 + "%" }}>
          <div className="subs-chart-tip-val">{window.fmtK(hover.value)}</div>
          <div className="subs-chart-tip-day">{fmtDate(hover.day)}</div>
        </div>
      )}
      <div className="subs-chart-chips">
        <button type="button"
                className={"subs-chip" + (platform === "all" ? " active" : "")}
                onClick={() => setPlatform("all")}>Все</button>
        {platformsSet.map(p => (
          <button key={p} type="button"
                  className={"subs-chip" + (platform === p ? " active" : "")}
                  onClick={() => setPlatform(p)}>{p}</button>
        ))}
      </div>
    </div>
  );
}

window.SubsChart = SubsChart;
