// ============================================================
// WC26 — shared components (from design handoff · data-shape driven)
// ============================================================
const { useState, useEffect, useRef, useMemo, useCallback } = React;

const fmtMoney = (v, sign) => {
  const a = Math.abs(v);
  const s = a >= 1e6 ? "$" + (a / 1e6).toFixed(1) + "M"
    : a >= 1000 ? "$" + (a / 1000).toFixed(a >= 10000 ? 1 : 2) + "k" : "$" + a.toFixed(0);
  return (v < 0 ? "−" : sign ? "+" : "") + s;
};
const fmtMoneyFull = (v, sign) =>
  (v < 0 ? "−$" : sign ? "+$" : "$") + Math.abs(v).toLocaleString("en-US", { maximumFractionDigits: 0 });
const fmtCents = (p) => (p == null ? "—" : (p * 100).toFixed(1) + "¢");
const fmtCents0 = (p) => (p == null ? "—" : Math.round(p * 100) + "¢");
const pnlClass = (v) => (v >= 0 ? "up" : "down");

// ---------- team roundel ----------
function TeamBadge({ code, size = 30 }) {
  const t = WC.TEAMS[code] || { c: ["#888", "#aaa"] };
  return (
    <span className="roundel" style={{
      width: size, height: size, fontSize: size * 0.36,
      background: `linear-gradient(135deg, ${t.c[0]} 0%, ${t.c[0]} 48%, ${t.c[1]} 52%, ${t.c[1]} 100%)`,
    }}>{code}</span>
  );
}

function TeamSide({ code, size = 30, nameStyle, reverse }) {
  const t = WC.TEAMS[code] || { name: code };
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 8, flexDirection: reverse ? "row-reverse" : "row" }}>
      <TeamBadge code={code} size={size} />
      <span className="bc-display" style={{ fontSize: size * 0.62, ...nameStyle }}>{t.name}</span>
    </span>
  );
}

// ---------- status pill ----------
function StatusPill({ status }) {
  if (status === "live") return <span className="bc-chip live"><span className="pulse-dot" style={{ background: "#fff" }}></span>Live</span>;
  if (status === "settled") return <span className="bc-chip ghost">Settled</span>;
  return <span className="bc-chip blue">Upcoming</span>;
}

// ---------- generic stat ----------
function Stat({ label, value, sub, tone, big }) {
  return (
    <div style={{ minWidth: 0 }}>
      <div className="bc-label" style={{ marginBottom: 4 }}>{label}</div>
      <div className={"bc-num " + (tone || "")} style={{ fontSize: big ? 28 : 20, fontWeight: 600, lineHeight: 1.05 }}>{value}</div>
      {sub ? <div style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 3 }}>{sub}</div> : null}
    </div>
  );
}

// ---------- price chart (SVG) ----------
function PriceChart({ series, markers = [], events = [], height = 220, domain, yDomain = [0, 1], liveDot, accent = "var(--sky)", xLabel, extras = [] }) {
  const wrapRef = useRef(null);
  const [w, setW] = useState(700);
  useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const ro = new ResizeObserver(() => setW(el.clientWidth));
    ro.observe(el);
    setW(el.clientWidth);
    return () => ro.disconnect();
  }, []);
  if (!series || series.length < 2) return (
    <div ref={wrapRef} style={{ height, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink-3)", fontSize: 12 }}>
      รอข้อมูลราคา…
    </div>
  );

  const PAD = { l: 34, r: 14, t: 10, b: 22 };
  const xs = series.map((d) => d.m);
  const dom = domain || [Math.min(...xs), Math.max(...xs)];
  const [y0, y1] = yDomain;
  const X = (m) => PAD.l + ((m - dom[0]) / (dom[1] - dom[0] || 1)) * (w - PAD.l - PAD.r);
  const Y = (p) => PAD.t + (1 - (p - y0) / (y1 - y0)) * (height - PAD.t - PAD.b);

  const line = series.map((d, i) => (i ? "L" : "M") + X(d.m).toFixed(1) + " " + Y(d.p).toFixed(1)).join(" ");
  const area = line + ` L ${X(series[series.length - 1].m).toFixed(1)} ${Y(y0)} L ${X(series[0].m).toFixed(1)} ${Y(y0)} Z`;
  const gridP = [0.25, 0.5, 0.75].filter((p) => p > y0 && p < y1);
  const last = series[series.length - 1];

  return (
    <div ref={wrapRef} style={{ width: "100%" }}>
      <svg width={w} height={height} style={{ display: "block" }}>
        <defs>
          <linearGradient id="pcFill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={accent} stopOpacity="0.18" />
            <stop offset="100%" stopColor={accent} stopOpacity="0.01" />
          </linearGradient>
        </defs>
        {gridP.map((p) => (
          <g key={p}>
            <line x1={PAD.l} x2={w - PAD.r} y1={Y(p)} y2={Y(p)} stroke="var(--line)" strokeDasharray="3 4" />
            <text x={4} y={Y(p) + 4} fontSize="10" fill="var(--ink-3)" fontFamily="var(--mono)">{Math.round(p * 100)}¢</text>
          </g>
        ))}
        {events.map((e, i) => {
          const x = X(e.m);
          if (x < PAD.l || x > w - PAD.r) return null;
          const isGoal = e.type === "goal";
          return (
            <g key={i}>
              <line x1={x} x2={x} y1={PAD.t} y2={height - PAD.b} stroke={isGoal ? "var(--gold)" : "var(--line-2)"} strokeWidth={isGoal ? 1.5 : 1} strokeDasharray={isGoal ? "" : "2 3"} />
              {isGoal ? <circle cx={x} cy={PAD.t + 5} r="4" fill="var(--gold)" /> : null}
              <text x={x + 4} y={height - PAD.b - 4} fontSize="9.5" fill="var(--ink-3)" fontFamily="var(--display)" style={{ textTransform: "uppercase", letterSpacing: ".06em" }}>
                {e.type === "goal" ? "GOAL " + (e.team || "") : e.type.toUpperCase()}
              </text>
            </g>
          );
        })}
        <path d={area} fill="url(#pcFill)" />
        {extras.map((ex, i) => {
          if (!ex.series || ex.series.length < 2) return null;
          const d = ex.series.map((pt, j) => (j ? "L" : "M") + X(pt.m).toFixed(1) + " " + Y(pt.p).toFixed(1)).join(" ");
          return <path key={"ex" + i} d={d} fill="none" stroke={ex.color} strokeWidth={ex.width || 1.2} strokeDasharray={ex.dash || ""} opacity={ex.opacity == null ? 0.65 : ex.opacity} strokeLinejoin="round" />;
        })}
        <path d={line} fill="none" stroke={accent} strokeWidth="2" strokeLinejoin="round" />
        {markers.map((mk, i) => (
          <g key={i} transform={`translate(${X(mk.m)},${Y(mk.p)})`}>
            {mk.kind === "buy"
              ? <path d="M0 -5.5 L5 3.5 L-5 3.5 Z" fill="var(--pitch)" stroke="#fff" strokeWidth="1.2" />
              : <path d="M0 5.5 L5 -3.5 L-5 -3.5 Z" fill="var(--hot)" stroke="#fff" strokeWidth="1.2" />}
          </g>
        ))}
        {liveDot ? (
          <g>
            <circle cx={X(last.m)} cy={Y(last.p)} r="8" fill={accent} opacity="0.18" />
            <circle cx={X(last.m)} cy={Y(last.p)} r="3.5" fill={accent} stroke="#fff" strokeWidth="1.5" />
          </g>
        ) : null}
        <text x={PAD.l} y={height - 6} fontSize="10" fill="var(--ink-3)" fontFamily="var(--mono)">{(xLabel || ((m) => Math.round(m) + "'"))(dom[0])}</text>
        <text x={w - PAD.r} y={height - 6} fontSize="10" fill="var(--ink-3)" fontFamily="var(--mono)" textAnchor="end">{(xLabel || ((m) => Math.round(m) + "'"))(dom[1])}</text>
      </svg>
    </div>
  );
}

// ---------- compact order book ladder ----------
function OrderBook({ book, last, lastDir, depthMax }) {
  if (!book || !book.asks || !book.bids || (!book.asks.length && !book.bids.length)) {
    return <div style={{ padding: 14, fontSize: 12, color: "var(--ink-3)" }}>order book ยังไม่เข้า — ตลาดอยู่นอก tracking window หรือรอ recorder</div>;
  }
  const asks = book.asks.slice(0, 5), bids = book.bids.slice(0, 5);
  const max = depthMax || Math.max(...asks.map((l) => l.q), ...bids.map((l) => l.q), 1);
  return (
    <div>
      <div className="ob-row" style={{ color: "var(--ink-3)", fontFamily: "var(--display)", textTransform: "uppercase", letterSpacing: ".1em", fontSize: 10.5 }}>
        <span>Price</span><span>Size</span>
      </div>
      {[...asks].reverse().map((l, i) => (
        <div className="ob-row ask" key={"a" + i}>
          <span className="ob-depth" style={{ width: Math.min(100, (l.q / max) * 100) + "%" }}></span>
          <span className="down">{fmtCents(l.p)}</span>
          <span style={{ color: "var(--ink-2)" }}>{l.q.toLocaleString()}</span>
        </div>
      ))}
      <div className={"ob-row " + (lastDir > 0 ? "flash-up" : lastDir < 0 ? "flash-down" : "")} key={"last" + last}
           style={{ borderTop: "1px solid var(--line)", borderBottom: "1px solid var(--line)", padding: "6px 10px", margin: "2px 0" }}>
        <span className={"bc-num " + (lastDir >= 0 ? "up" : "down")} style={{ fontSize: 17, fontWeight: 600 }}>
          {fmtCents(last)} {lastDir > 0 ? "▲" : lastDir < 0 ? "▼" : ""}
        </span>
        <span className="bc-label" style={{ fontSize: 10 }}>Mid</span>
      </div>
      {bids.map((l, i) => (
        <div className="ob-row bid" key={"b" + i}>
          <span className="ob-depth" style={{ width: Math.min(100, (l.q / max) * 100) + "%" }}></span>
          <span className="up">{fmtCents(l.p)}</span>
          <span style={{ color: "var(--ink-2)" }}>{l.q.toLocaleString()}</span>
        </div>
      ))}
    </div>
  );
}

// ---------- bottom ticker (live lines from sweeps) ----------
function Ticker() {
  useStore();
  const items = (WC.FIXTURES || [])
    .filter((f) => f.status !== "settled" && f.odds && f.odds.home != null)
    .slice(0, 24)
    .map((f) => ({ label: `${f.home} v ${f.away}`, h: f.odds.home, d: f.odds.draw, a: f.odds.away, live: f.status === "live" }));
  if (!items.length) return null;
  const doubled = [...items, ...items];
  return (
    <div style={{ position: "fixed", left: 0, right: 0, bottom: 0, zIndex: 40, background: "var(--chrome)", color: "#fff", overflow: "hidden", borderTop: "3px solid var(--pitch)" }}>
      <div style={{ display: "flex", alignItems: "stretch" }}>
        <div className="bc-display" style={{ flex: "none", background: "var(--pitch)", color: "#fff", fontSize: 13, padding: "8px 14px", display: "flex", alignItems: "center", zIndex: 2 }}>
          WC26 · Markets
        </div>
        <div style={{ overflow: "hidden", flex: 1 }}>
          <div className="ticker-track">
            {doubled.map((it, i) => (
              <span key={i} className="bc-mono" style={{ fontSize: 12, padding: "9px 26px 8px 0", display: "inline-flex", gap: 9, alignItems: "baseline" }}>
                {it.live ? <span style={{ color: "var(--hot)", fontFamily: "var(--display)", fontWeight: 700, letterSpacing: ".08em" }}>● LIVE</span> : null}
                <span style={{ fontFamily: "var(--display)", fontWeight: 600, letterSpacing: ".05em", color: "rgba(255,255,255,.92)" }}>{it.label}</span>
                <span style={{ color: "oklch(0.8 0.13 152)" }}>{fmtCents0(it.h)}</span>
                <span style={{ color: "rgba(255,255,255,.5)" }}>{fmtCents0(it.d)}</span>
                <span style={{ color: "oklch(0.8 0.1 25)" }}>{fmtCents0(it.a)}</span>
                <span style={{ color: "rgba(255,255,255,.25)" }}>/</span>
              </span>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------- thai hint ----------
function ThaiHint({ children }) {
  return <div className="thai-hint" style={{ fontSize: 12, color: "var(--ink-3)", lineHeight: 1.55 }}>{children}</div>;
}

// ---------- timeframe tabs ----------
function TfTabs({ value, options, onChange }) {
  return (
    <span style={{ display: "inline-flex", gap: 4, flexWrap: "wrap" }}>
      {options.map(([k, label]) => (
        <button key={k} onClick={() => onChange(k)}
          style={{
            padding: "3px 10px", fontSize: 11, cursor: "pointer",
            fontFamily: "var(--display)", fontWeight: 600, letterSpacing: ".05em", textTransform: "uppercase",
            background: value === k ? "var(--pitch)" : "transparent",
            color: value === k ? "#fff" : "var(--ink-2)",
            border: "1px solid " + (value === k ? "var(--pitch)" : "var(--line-2)"),
            borderRadius: 5, transition: "all .15s ease"
          }}>
          {label}
        </button>
      ))}
    </span>
  );
}

// ---------- phase-1 placeholder ----------
function Phase1Note({ children }) {
  return (
    <div style={{ padding: 14, display: "flex", gap: 10, alignItems: "center" }}>
      <span className="bc-chip gold">Phase 1</span>
      <ThaiHint>{children || "ส่วนนี้จะติดไฟเมื่อ wc-trader เริ่มเทรด (paper) — ตอนนี้ระบบอยู่โหมด recording"}</ThaiHint>
    </div>
  );
}

Object.assign(window, {
  fmtMoney, fmtMoneyFull, fmtCents, fmtCents0, pnlClass,
  TeamBadge, TeamSide, StatusPill, Stat, PriceChart, OrderBook, Ticker, ThaiHint, Phase1Note, TfTabs,
});
