// Turnix — shared shell, state, primitives
// Loaded as a Babel JSX file. Exposes globals via window.

// ──────────────────────────────────────────────────────────────────────────
// Fake players & helpers
// ──────────────────────────────────────────────────────────────────────────
const PLAYER_POOL = [
  { name: "Mara",   color: "#ff8b4a" },
  { name: "Theo",   color: "#4ea1ff" },
  { name: "Zia",    color: "#b48bff" },
  { name: "Kojo",   color: "#3ddc8a" },
  { name: "Iris",   color: "#ffb547" },
  { name: "Vee",    color: "#ff5470" },
  { name: "Noor",   color: "#7be0ff" },
  { name: "Rune",   color: "#c47bff" },
];

function makePlayers(youName, count) {
  const others = PLAYER_POOL.slice(0, Math.max(0, count - 1)).map((p, i) => ({
    id: `p${i + 1}`,
    name: p.name,
    color: p.color,
    ready: false,
    you: false,
    host: false,
    speaking: false,
    score: 0,
  }));
  const you = {
    id: "you",
    name: youName || "You",
    color: "#f5f6f8",
    ready: false,
    you: true,
    host: true,
    speaking: false,
    score: 0,
  };
  return [you, ...others];
}

// Simple seeded shuffle so things look random but stable
function shuffle(arr, seed = 1) {
  const a = arr.slice();
  let s = seed;
  for (let i = a.length - 1; i > 0; i--) {
    s = (s * 9301 + 49297) % 233280;
    const j = Math.floor((s / 233280) * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

function clsx(...xs) { return xs.filter(Boolean).join(" "); }

function initials(name) {
  return name.trim().split(/\s+/).map(x => x[0]).slice(0, 2).join("").toUpperCase();
}

// ──────────────────────────────────────────────────────────────────────────
// Background (animated gradient + particles)
// ──────────────────────────────────────────────────────────────────────────
function Background({ mode = "animated", particles = true, accent }) {
  // accent tint shifts the background subtly per game
  const tintStyle = accent ? {
    background: `radial-gradient(80% 60% at 50% 0%, ${accent}22, transparent 60%)`,
    position: "absolute", inset: 0, pointerEvents: "none",
    transition: "background 600ms ease",
  } : null;

  const cls = "tx-bg" + (mode === "static" ? " static" : mode === "off" ? " flat" : "");

  // memoized particles so they don't re-randomize every render
  const dots = React.useMemo(() => {
    if (!particles) return [];
    return Array.from({ length: 28 }).map((_, i) => ({
      left: Math.random() * 100,
      delay: Math.random() * -30,
      dur: 18 + Math.random() * 22,
      size: 1 + Math.random() * 2,
      opacity: 0.3 + Math.random() * 0.5,
    }));
  }, [particles]);

  return (
    <div className={cls} aria-hidden="true">
      {accent && <div style={tintStyle} />}
      {particles && (
        <div className="tx-particles">
          {dots.map((d, i) => (
            <span key={i} style={{
              left: `${d.left}%`,
              bottom: `-4px`,
              width: `${d.size}px`, height: `${d.size}px`,
              animationDuration: `${d.dur}s`,
              animationDelay: `${d.delay}s`,
              opacity: d.opacity,
            }} />
          ))}
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Logo + chips
// ──────────────────────────────────────────────────────────────────────────
function Logo({ size = "md" }) {
  return (
    <span className="tx-logo" style={size === "lg" ? { fontSize: 22 } : {}}>
      <span className="tx-logo-mark" style={size === "lg" ? { width: 28, height: 28, borderRadius: 9 } : {}} />
      Turnix
    </span>
  );
}

function Chip({ children, className = "", mono = false, ...rest }) {
  return <span className={clsx("tx-chip", mono && "mono", className)} {...rest}>{children}</span>;
}

function StatusDot({ kind = "default" }) {
  return <span className={clsx("tx-dot", kind !== "default" && kind)} />;
}

// ──────────────────────────────────────────────────────────────────────────
// Discord widget — voice-channel indicator
// ──────────────────────────────────────────────────────────────────────────
function DiscordWidget({ channel = "Turnix Voice", count = 6, muted = false, onToggle }) {
  return (
    <button
      type="button"
      onClick={onToggle}
      className={clsx("tx-discord", muted && "muted")}
      style={{ border: "1px solid rgba(88,101,242,0.28)", cursor: "pointer" }}
      aria-label={muted ? "Unmute" : "Mute"}
    >
      <span className="tx-discord-mark">D</span>
      <span style={{ display: "flex", flexDirection: "column", lineHeight: 1.05, alignItems: "flex-start" }}>
        <span style={{ fontSize: 11, opacity: 0.7 }}>Discord · {count}</span>
        <span style={{ fontSize: 12, fontWeight: 600 }}>{channel}</span>
      </span>
      <span className="dc-mic" title={muted ? "Mic muted" : "Mic on"}>
        {muted ? "✕" : "●"}
      </span>
    </button>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Avatar
// ──────────────────────────────────────────────────────────────────────────
function Avatar({ player, size = 36, showName = false, speaking = false }) {
  const cls = clsx("tx-avatar", player.ready && "ready", player.host && "host", speaking && "speaking");
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 10 }}>
      <span className={cls} style={{
        width: size, height: size,
        background: player.color,
        color: shouldUseDarkText(player.color) ? "#0a0b10" : "#fff",
        fontSize: size <= 28 ? 11 : 13,
      }}>
        {initials(player.name)}
      </span>
      {showName && (
        <span style={{ fontSize: 14, fontWeight: 500 }}>
          {player.name}{player.you && <span style={{ opacity: 0.45, fontWeight: 400 }}> · you</span>}
        </span>
      )}
    </span>
  );
}

function shouldUseDarkText(hex) {
  // crude luminance check
  const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/i.exec(hex);
  if (!m) return false;
  const r = parseInt(m[1], 16), g = parseInt(m[2], 16), b = parseInt(m[3], 16);
  const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
  return lum > 0.62;
}

// ──────────────────────────────────────────────────────────────────────────
// Top bar (game screen)
// ──────────────────────────────────────────────────────────────────────────
function TopBar({ left, center, right }) {
  return (
    <header className="tx-topbar">
      <div className="left">{left}</div>
      <div className="center">{center}</div>
      <div className="right">{right}</div>
    </header>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Timer ring
// ──────────────────────────────────────────────────────────────────────────
function TimerRing({ value, max, accent = "var(--fg-0)", size = 28 }) {
  const r = (size - 4) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.max(0, Math.min(1, value / max));
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="rgba(255,255,255,0.1)" strokeWidth="2" />
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={accent} strokeWidth="2"
          strokeDasharray={c} strokeDashoffset={c * (1 - pct)}
          strokeLinecap="round"
          transform={`rotate(-90 ${size/2} ${size/2})`}
          style={{ transition: "stroke-dashoffset 200ms linear" }} />
      </svg>
      <span style={{ fontFamily: "var(--font-mono)", fontSize: 13, fontVariantNumeric: "tabular-nums", color: "var(--fg-1)" }}>
        {value}s
      </span>
    </span>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// useCountdown — drives turn timers
// ──────────────────────────────────────────────────────────────────────────
function useCountdown(seconds, { running = true, onEnd, key } = {}) {
  const [t, setT] = React.useState(seconds);
  React.useEffect(() => { setT(seconds); }, [seconds, key]);
  React.useEffect(() => {
    if (!running) return;
    if (t <= 0) { onEnd && onEnd(); return; }
    const id = setTimeout(() => setT(v => v - 1), 1000);
    return () => clearTimeout(id);
  }, [t, running]);
  return [t, setT];
}

// ──────────────────────────────────────────────────────────────────────────
// Game accents
// ──────────────────────────────────────────────────────────────────────────
const GAMES = {
  impostor: {
    id: "impostor",
    name: "Word Impostor",
    short: "Sniff out the player with a different word.",
    accent: "var(--p-impostor)",
    accentRaw: "#b48bff",
    glow: "var(--glow-impostor)",
  },
  letter: {
    id: "letter",
    name: "Letter Game",
    short: "Add a letter without finishing a word. Bluff or call.",
    accent: "var(--p-letter)",
    accentRaw: "#4ea1ff",
    glow: "var(--glow-letter)",
  },
  wrong: {
    id: "wrong",
    name: "Wrong Answer Wins",
    short: "Be wrong. Be unique. Don't get caught matching.",
    accent: "var(--p-wrong)",
    accentRaw: "#ff8b4a",
    glow: "var(--glow-wrong)",
  },
};

Object.assign(window, {
  GAMES, PLAYER_POOL, makePlayers, shuffle, clsx, initials,
  Background, Logo, Chip, StatusDot, DiscordWidget, Avatar,
  TopBar, TimerRing, useCountdown, shouldUseDarkText,
});
