/* MBEX — shared helpers and UI primitives for the new Mini App shell */

function AreaChart({ data, w = 326, h = 120, pad = 6, color = "acc", showDot = true }) {
  const input = Array.isArray(data) && data.length ? data : [0, 0];
  const points = input.length === 1 ? [input[0], input[0]] : input;
  const min = Math.min(...points);
  const max = Math.max(...points);
  const range = max - min || 1;
  const innerH = h - pad * 2;
  const coords = points.map((value, index) => ({
    x: pad + (index / Math.max(1, points.length - 1)) * (w - pad * 2),
    y: pad + (1 - (value - min) / range) * innerH,
  }));

  function smoothPath(list) {
    if (list.length < 2) {
      return "";
    }
    let path = `M ${list[0].x} ${list[0].y}`;
    for (let index = 0; index < list.length - 1; index += 1) {
      const current = list[index];
      const next = list[index + 1];
      const cx = (current.x + next.x) / 2;
      path += ` C ${cx} ${current.y}, ${cx} ${next.y}, ${next.x} ${next.y}`;
    }
    return path;
  }

  const line = smoothPath(coords);
  const area = `${line} L ${coords[coords.length - 1].x} ${h} L ${coords[0].x} ${h} Z`;
  const accent = color === "pos" ? "var(--pos)" : "var(--accent)";
  const gradientId = `chart_${color}_${points.length}_${Math.round(points[0] || 0)}`;
  const last = coords[coords.length - 1];

  return (
    <svg width="100%" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ display: "block" }}>
      <defs>
        <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={accent} stopOpacity="0.26" />
          <stop offset="100%" stopColor={accent} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill={`url(#${gradientId})`} />
      <path d={line} fill="none" stroke={accent} strokeWidth="2.4" vectorEffect="non-scaling-stroke" />
      {showDot && (
        <circle
          cx={last.x}
          cy={last.y}
          r="3.8"
          fill={accent}
          stroke="var(--surface)"
          strokeWidth="2"
        />
      )}
    </svg>
  );
}

function monotoneCubicPath(points) {
  if (points.length < 2) {
    return points.length ? `M ${points[0].x} ${points[0].y}` : "";
  }

  const slopes = [];
  for (let index = 0; index < points.length - 1; index += 1) {
    const width = points[index + 1].x - points[index].x;
    slopes.push(width ? (points[index + 1].y - points[index].y) / width : 0);
  }

  const tangents = points.map((_, index) => {
    if (index === 0) {
      return slopes[0];
    }
    if (index === points.length - 1) {
      return slopes[slopes.length - 1];
    }
    const previous = slopes[index - 1];
    const next = slopes[index];
    if (previous === 0 || next === 0 || previous * next < 0) {
      return 0;
    }
    return (2 * previous * next) / (previous + next);
  });

  let path = `M ${points[0].x} ${points[0].y}`;
  for (let index = 0; index < points.length - 1; index += 1) {
    const current = points[index];
    const next = points[index + 1];
    const width = next.x - current.x;
    path += ` C ${(current.x + width / 3).toFixed(1)} ${(current.y + tangents[index] * width / 3).toFixed(1)}, ${(next.x - width / 3).toFixed(1)} ${(next.y - tangents[index + 1] * width / 3).toFixed(1)}, ${next.x} ${next.y}`;
  }
  return path;
}

function formatRateAxis(value, fallback) {
  if (!value || !Number.isFinite(Date.parse(value))) {
    return fallback;
  }
  return new Date(Date.parse(value)).toLocaleTimeString("ru-RU", {
    hour: "2-digit",
    minute: "2-digit",
    timeZone: "Europe/Moscow",
  });
}

let heroRateChartHasRevealed = false;

function HeroRateChart({ data, updatedAt = "", w = 326, h = 116, pad = 6 }) {
  const source = Array.isArray(data) && data.length ? data : [0, 0];
  const rawPoints = source.length === 1 ? [source[0], source[0]] : source;
  const points = rawPoints.map((item) => ({
    value: Number(typeof item === "object" ? item.value : item) || 0,
    timestamp: typeof item === "object" ? item.timestamp || "" : "",
  }));
  const min = Math.min(...points.map((point) => point.value));
  const max = Math.max(...points.map((point) => point.value));
  const range = max - min || 1;
  const innerH = h - pad * 2;
  const [activeIndex, setActiveIndex] = React.useState(null);
  const [isRevealing, setIsRevealing] = React.useState(false);
  const activeIndexRef = React.useRef(null);
  const hasLoadedHistory = points.some((point) => (
    point.timestamp && Number.isFinite(Date.parse(point.timestamp))
  ));

  React.useLayoutEffect(() => {
    if (heroRateChartHasRevealed || !hasLoadedHistory) {
      return;
    }
    heroRateChartHasRevealed = true;
    setIsRevealing(true);
  }, [hasLoadedHistory]);

  React.useEffect(() => {
    activeIndexRef.current = null;
    setActiveIndex(null);
  }, [data]);
  const coords = points.map((point, index) => ({
    x: Number((pad + (index / Math.max(1, points.length - 1)) * (w - pad * 2)).toFixed(1)),
    y: Number((pad + (1 - (point.value - min) / range) * innerH).toFixed(1)),
  }));

  const line = monotoneCubicPath(coords);
  const area = `${line} L ${coords[coords.length - 1].x} ${h} L ${coords[0].x} ${h} Z`;
  const activePoint = activeIndex === null ? null : points[activeIndex];
  const activeCoord = activeIndex === null ? null : coords[activeIndex];
  const activeTime = activePoint?.timestamp || updatedAt;
  const activeTimeLabel = activeTime && Number.isFinite(Date.parse(activeTime))
    ? new Date(Date.parse(activeTime)).toLocaleString("ru-RU", {
      day: "2-digit",
      month: "2-digit",
      hour: "2-digit",
      minute: "2-digit",
      timeZone: "Europe/Moscow",
    })
    : "Время неизвестно";
  const axisIndexes = [0, 0.25, 0.5, 0.75, 1].map((position) => (
    Math.round(position * (points.length - 1))
  ));
  const fallbackAxis = ["00:00", "06:00", "12:00", "18:00", "24:00"];

  function selectPoint(event) {
    const rect = event.currentTarget.getBoundingClientRect();
    if (!rect.width) {
      return;
    }
    const progress = Math.max(0, Math.min(1, (event.clientX - rect.left) / rect.width));
    const nextIndex = Math.round(progress * (points.length - 1));
    if (activeIndexRef.current !== nextIndex) {
      activeIndexRef.current = nextIndex;
      const haptic = window.Telegram?.WebApp?.HapticFeedback;
      if (haptic?.selectionChanged) {
        haptic.selectionChanged();
      }
    }
    setActiveIndex(nextIndex);
  }

  function clearSelection() {
    activeIndexRef.current = null;
    setActiveIndex(null);
  }

  return (
    <div className={`hero-rate-chart ${isRevealing ? "is-revealing" : ""}`}>
      <svg
        width="100%"
        viewBox={`0 0 ${w} ${h}`}
        preserveAspectRatio="none"
        role="img"
        aria-label="Почасовой график курса за последние 24 часа"
        onPointerDown={selectPoint}
        onPointerMove={selectPoint}
        onPointerLeave={clearSelection}
      >
        <defs>
          <linearGradient id="hero_rate_chart_fill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#ffffff" stopOpacity="0.34" />
            <stop offset="100%" stopColor="#ffffff" stopOpacity="0" />
          </linearGradient>
        </defs>
        <line className="hero-rate-grid" x1="0" y1="38" x2={w} y2="38" />
        <line className="hero-rate-grid" x1="0" y1="80" x2={w} y2="80" />
        <g className="hero-rate-plot">
          <path className="hero-rate-area" d={area} fill="url(#hero_rate_chart_fill)" />
          <path className="hero-rate-line" d={line} pathLength="1" />
          <g className="hero-rate-last-point">
            <circle className="hero-rate-last-halo" cx={coords[coords.length - 1].x} cy={coords[coords.length - 1].y} r="8" />
            <circle className="hero-rate-last-marker" cx={coords[coords.length - 1].x} cy={coords[coords.length - 1].y} r="4" />
          </g>
        </g>
        {activeCoord ? <line className="hero-rate-cursor" x1={activeCoord.x} y1="0" x2={activeCoord.x} y2={h} /> : null}
        {activeCoord ? <circle className="hero-rate-cursor-dot" cx={activeCoord.x} cy={activeCoord.y} r="5" /> : null}
      </svg>
      {activeCoord ? (
        <div
          className="hero-rate-tooltip"
          style={{ left: `${(activeCoord.x / w) * 100}%`, top: `${(activeCoord.y / h) * 100}%` }}
          aria-live="polite"
        >
          <strong>{window.MBEX.fmtRub2(activePoint.value)} ₽</strong>
          <span>{activeTimeLabel}</span>
        </div>
      ) : null}
      <div className="hero-rate-axis">
        {axisIndexes.map((index, axisIndex) => (
          <span key={`${index}-${axisIndex}`}>
            {formatRateAxis(points[index]?.timestamp, fallbackAxis[axisIndex])}
          </span>
        ))}
      </div>
    </div>
  );
}

function Coin({ kind }) {
  return (
    <div className={`coin ${kind === "usdt" ? "coin-usdt" : "coin-rub"}`}>
      {kind === "usdt" ? "₮" : "₽"}
    </div>
  );
}

function Pill({ cls = "pill-muted", dot, children }) {
  return (
    <span className={`pill ${cls}`}>
      {dot ? <span className="dot" style={{ background: dot }} /> : null}
      {children}
    </span>
  );
}

function Segmented({ value, onChange, options }) {
  return (
    <div className="seg">
      {options.map((option) => (
        <div
          key={option.value}
          className={`seg-item ${value === option.value ? `active ${option.tone || ""}` : ""}`}
          onClick={() => onChange(option.value)}
        >
          {option.icon}
          {option.label}
        </div>
      ))}
    </div>
  );
}

function Stepper({ current = 1, labels = [] }) {
  const safeLabels = labels.length ? labels : ["Создана", "В работе", "Завершена"];
  return (
    <div className="steps">
      {safeLabels.map((label, index) => {
        const stepNumber = index + 1;
        const done = stepNumber < current;
        const active = stepNumber === current;
        return (
          <div key={label} className={`step ${done ? "done" : ""} ${active ? "active" : ""}`}>
            {index < safeLabels.length - 1 ? <div className="step-line" /> : null}
            <div className="step-dot">
              {done ? <Icons.check size={14} sw={2.6} /> : stepNumber}
            </div>
            <div className="step-lbl">{label}</div>
          </div>
        );
      })}
    </div>
  );
}

function Row({ icon, accent, title, sub, detail, onClick, chevron = true }) {
  return (
    <div className="row" onClick={onClick}>
      {icon ? <div className={`row-ic ${accent ? "accent" : ""}`}>{icon}</div> : null}
      <div className="grow" style={{ minWidth: 0 }}>
        <div style={{ fontWeight: 700, fontSize: 15, color: "var(--text)" }}>{title}</div>
        {sub ? <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>{sub}</div> : null}
      </div>
      {detail ? (
        <span className="muted" style={{ fontSize: 13, fontWeight: 700, marginLeft: "auto", whiteSpace: "nowrap" }}>
          {detail}
        </span>
      ) : null}
      {chevron ? <Icons.chevR className="chev" style={{ marginLeft: detail ? 8 : "auto" }} /> : null}
    </div>
  );
}

function CopyField({ label, value, mono = true, actionLabel, onCopied, wrapValue = false }) {
  const [copied, setCopied] = React.useState(false);

  async function handleCopy() {
    const ok = await window.MBEX.copyText(value);
    if (ok) {
      setCopied(true);
      window.setTimeout(() => setCopied(false), 1400);
      if (onCopied) {
        onCopied(value);
      }
    }
  }

  return (
    <div>
      {label ? <span className="field-lbl">{label}</span> : null}
      <div
        className={`field copy-field${wrapValue ? " has-wrapping-value" : ""}`}
        style={{ display: "flex", alignItems: "center", gap: 10, cursor: "pointer" }}
        onClick={handleCopy}
      >
        <span
          className={`${mono ? "num " : ""}copy-field-value${wrapValue ? " wallet-address-full" : ""}`}
        >
          {value}
        </span>
        <span style={{ color: copied ? "var(--pos)" : "var(--accent)", display: "grid", placeItems: "center" }}>
          {copied ? <Icons.check size={18} sw={2.4} /> : <Icons.copy size={18} />}
        </span>
      </div>
      {actionLabel ? (
        <div className="muted" style={{ marginTop: 6, fontSize: 12 }}>
          {actionLabel}
        </div>
      ) : null}
    </div>
  );
}

function SummaryRow({ label, value, strong, tone }) {
  const color = tone === "pos" ? "var(--pos)" : tone === "neg" ? "var(--neg)" : "var(--text)";
  return (
    <div className="between" style={{ padding: "9px 0", gap: 12 }}>
      <span className="muted" style={{ fontSize: 13.5, whiteSpace: "nowrap" }}>{label}</span>
      <span
        style={{
          fontSize: strong ? 16 : 14,
          fontWeight: strong ? 800 : 700,
          whiteSpace: "nowrap",
          color,
          fontFamily: "var(--font-num)",
        }}
      >
        {value}
      </span>
    </div>
  );
}

function EmptyState({ icon, title, text }) {
  return (
    <div className="empty-card">
      <div style={{ display: "flex", justifyContent: "center", color: "var(--text-3)" }}>
        {icon}
      </div>
      <div style={{ marginTop: 10, fontWeight: 700, color: "var(--text)" }}>{title}</div>
      <div style={{ marginTop: 6 }}>{text}</div>
    </div>
  );
}

window.AreaChart = AreaChart;
window.HeroRateChart = HeroRateChart;
window.Coin = Coin;
window.Pill = Pill;
window.Segmented = Segmented;
window.Stepper = Stepper;
window.Row = Row;
window.CopyField = CopyField;
window.SummaryRow = SummaryRow;
window.EmptyState = EmptyState;
