// components.jsx — shared visual components
// Exports: Card, Pip, HUD, Marquee, Modal, BulbStrip, ScoreStrip
// All attached to window at the end for cross-file scope.

const { useEffect, useRef, useState } = React;

// ─── Pip ─────────────────────────────────────────────────────────────────────
// pts: 1|2|3 · diff: easy|medium|hard · metaphor: "num"|"dots"|"bars" · size: "default"|"small"|"tiny"
function Pip({ pts, diff, metaphor = "num", size = "default" }) {
  const klass = `pip ${size !== "default" ? size : ""} ${metaphor === "dots" ? "dots" : ""} ${metaphor === "bars" ? "bars" : ""}`;
  if (metaphor === "dots") {
    return (
      <span className={klass} data-diff={diff}>
        {Array.from({ length: pts }).map((_, i) => <i key={i} className="dot" />)}
      </span>
    );
  }
  if (metaphor === "bars") {
    return (
      <span className={klass} data-diff={diff}>
        {Array.from({ length: pts }).map((_, i) => (
          <i key={i} className="bar" style={{ height: 8 + i * 5 }} />
        ))}
      </span>
    );
  }
  return <span className={klass} data-diff={diff}>{pts}</span>;
}

// ─── Card ────────────────────────────────────────────────────────────────────
// word, pts, diff, time, state: "face"|"back"|"selected"|"won"|"blasted"|"active"|"dim"|"waiting"
// size: "lg"|"md"|"sm", metaphor, onClick, style
function Card({
  word, pts, diff, time,
  state = "face",
  size = "md",
  metaphor = "num",
  showTime = true,
  onClick,
  style,
  fontScale = 1,
}) {
  const klass = [
    "card",
    `size-${size}`,
    state === "back" ? "back" : "",
    state === "selected" ? "selected" : "",
    state === "won" ? "won" : "",
    state === "blasted" ? "blasted" : "",
    state === "active" ? "active" : "",
    state === "dim" || state === "waiting" ? "dim" : "",
  ].join(" ");

  const wordSize = size === "lg" ? 48 * fontScale
                : size === "md" ? 28 * fontScale
                : 18 * fontScale;

  const isInteractive = !!onClick && !["won", "blasted", "waiting", "dim"].includes(state);

  return (
    <div
      className={klass}
      style={style}
      role={isInteractive ? "button" : undefined}
      tabIndex={isInteractive ? 0 : -1}
      onClick={onClick}
      onKeyDown={(e) => {
        if (!isInteractive) return;
        if (e.key === "Enter" || e.key === " ") {
          e.preventDefault();
          onClick && onClick();
        }
      }}
    >
      <div className="grain" />
      <div className="corner-stripe" />
      <div className="card-face">
        <div className="card-head">
          <Pip pts={pts} diff={diff} metaphor={metaphor} />
          <div className="card-tier">
            {window.DIFF_LABEL?.[diff] || diff}
            {showTime && time != null ? <><br/>{time}s</> : null}
          </div>
        </div>
        <div className="card-word" style={{ fontSize: wordSize }}>{word}</div>
        <div className="card-foot">
          <span>{window.DIFF_LABEL?.[diff] || diff}</span>
          <Pip pts={pts} diff={diff} metaphor={metaphor} size="small" />
        </div>
      </div>
    </div>
  );
}

// ─── Marquee ─────────────────────────────────────────────────────────────────
function BulbStrip({ count = 8 }) {
  return (
    <div className="bulbs" aria-hidden="true">
      {Array.from({ length: count }).map((_, i) => <i key={i} />)}
    </div>
  );
}

function Marquee({ title, subtitle, mini = false }) {
  return (
    <div style={{
      textAlign: "center",
      padding: mini ? "8px 0 4px" : "24px 0 14px",
      position: "relative",
    }}>
      <BulbStrip count={mini ? 6 : 8} />
      <h1 style={{
        fontFamily: "var(--font-display)",
        fontSize: mini ? 26 : 44,
        margin: "10px 0 4px",
        letterSpacing: "-1px",
        background: "linear-gradient(180deg, var(--accent-2) 0%, var(--accent) 70%)",
        WebkitBackgroundClip: "text",
        WebkitTextFillColor: "transparent",
        textShadow: "0 0 30px rgba(255, 94, 58, 0.4)",
        textTransform: "uppercase",
        lineHeight: 1,
      }}>{title}</h1>
      {subtitle && (
        <div style={{
          fontFamily: "var(--font-arcade)",
          fontSize: 10,
          letterSpacing: 3,
          color: "var(--fg-quiet)",
          marginTop: 4,
          textTransform: "uppercase",
        }}>{subtitle}</div>
      )}
      <BulbStrip count={mini ? 6 : 8} />
    </div>
  );
}

// ─── HUD ─────────────────────────────────────────────────────────────────────
function HUD({ teams, activeIdx, round, totalRounds, onExit, onPlayerClick, lockActive }) {
  return (
    <div className="hud">
      {teams.map((t, i) => {
        const isActive = i === activeIdx;
        const canRemove = !!onPlayerClick && !(lockActive && isActive);
        return (
          <button
            key={i}
            className={"hud-team " + (isActive ? "active" : "")}
            onClick={canRemove ? () => onPlayerClick(i) : undefined}
            disabled={!canRemove}
            title={canRemove ? `Remove ${t.name}` : "Can't remove the active team mid-turn"}
            style={{
              appearance: "none",
              cursor: canRemove ? "pointer" : "default",
              font: "inherit",
            }}
          >
            <span className="nm">{t.name}</span>
            <span className="sc">{t.score}</span>
          </button>
        );
      })}
      <div className="hud-round">
        <b>RND</b><br />
        {round}/{totalRounds}
      </div>
      <button className="hud-exit" onClick={onExit} aria-label="Exit game">✕</button>
    </div>
  );
}

// ─── Modal ───────────────────────────────────────────────────────────────────
function Modal({
  icon, title, body,
  confirmLabel, cancelLabel,
  tertiaryLabel, onTertiary,
  onConfirm, onCancel,
  danger = true,
}) {
  const stacked = !!tertiaryLabel;
  return (
    <div className="modal-bg" onClick={onCancel}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        {icon && <div style={{ fontSize: 44, marginBottom: 10 }}>{icon}</div>}
        <div style={{
          fontFamily: "var(--font-display)",
          fontSize: 24,
          marginBottom: 8,
          color: "var(--fg)",
        }}>{title}</div>
        {body && <div style={{
          fontSize: 14,
          color: "var(--fg-dim)",
          marginBottom: 22,
          lineHeight: 1.5,
        }}>{body}</div>}
        <div style={{
          display: "flex",
          flexDirection: stacked ? "column" : "row",
          gap: 10,
        }}>
          {confirmLabel && (
            <button className={"btn " + (danger ? "danger" : "")} onClick={onConfirm}>{confirmLabel}</button>
          )}
          {tertiaryLabel && (
            <button className="btn go" onClick={onTertiary}>{tertiaryLabel}</button>
          )}
          <button className="btn secondary" onClick={onCancel}>{cancelLabel}</button>
        </div>
      </div>
    </div>
  );
}

// ─── ScoreStrip (used in result) ─────────────────────────────────────────────
function ScoreStrip({ teams, activeIdx }) {
  return (
    <div style={{ display: "flex", gap: 8, width: "100%" }}>
      {teams.map((t, i) => (
        <div key={i} style={{
          flex: 1,
          background: i === activeIdx ? "rgba(255, 94, 58, 0.18)" : "rgba(255, 255, 255, 0.04)",
          border: i === activeIdx ? "1px solid rgba(255, 94, 58, 0.45)" : "1px solid rgba(255, 255, 255, 0.06)",
          borderRadius: 10,
          padding: "8px 6px",
          textAlign: "center",
        }}>
          <div style={{
            fontFamily: "var(--font-arcade)",
            fontSize: 8,
            letterSpacing: 2,
            color: i === activeIdx ? "var(--accent)" : "var(--fg-quiet)",
            marginBottom: 4,
            whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
          }}>{t.name}</div>
          <div style={{
            fontFamily: "var(--font-arcade)",
            fontSize: 18,
            color: i === activeIdx ? "var(--accent)" : "var(--fg)",
          }}>{t.score}</div>
        </div>
      ))}
    </div>
  );
}

// ─── CountUp number (used in result) ─────────────────────────────────────────
function CountUp({ to, duration = 900, style }) {
  const [n, setN] = useState(0);
  useEffect(() => {
    if (to <= 0) { setN(0); return; }
    let start = null;
    let raf;
    const step = (ts) => {
      if (!start) start = ts;
      const p = Math.min(1, (ts - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setN(Math.round(eased * to));
      if (p < 1) raf = requestAnimationFrame(step); else {
        if (window.sfx) window.sfx.success();
      }
    };
    raf = requestAnimationFrame(step);

    // ticker sound during count up
    let ticks = 0;
    const tickInt = setInterval(() => {
      ticks++;
      if (window.sfx) window.sfx.score();
      if (ticks > duration / 80) clearInterval(tickInt);
    }, 80);

    return () => { if (raf) cancelAnimationFrame(raf); clearInterval(tickInt); };
  }, [to, duration]);
  return <span style={style}>{n}</span>;
}

// ─── Confetti — overlay of falling coloured pieces ────────────────────────────
function Confetti() {
  const COLORS = ['var(--accent)', 'var(--accent-2)', 'var(--good)', '#fff', '#ff9fe5', '#7dffd0', '#a0f0ff'];
  const ANIMS  = ['confettiFall0', 'confettiFall1', 'confettiFall2', 'confettiFall3'];
  const pieces = Array.from({ length: 26 }, (_, i) => ({
    left:     `${(i * 3.9 + 1.5) % 97}%`,
    color:    COLORS[i % COLORS.length],
    delay:    `${((i * 0.09) % 1.1).toFixed(2)}s`,
    height:   6 + (i % 5) * 4,
    width:    5 + (i % 4) * 3,
    duration: `${1.8 + (i % 6) * 0.28}s`,
    anim:     ANIMS[i % ANIMS.length],
  }));

  return (
    <div style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 50, overflow: 'hidden' }}>
      {pieces.map((p, i) => (
        <div key={i} style={{
          position: 'absolute',
          top: -24,
          left: p.left,
          width: p.width,
          height: p.height,
          background: p.color,
          borderRadius: i % 3 === 0 ? '50%' : 2,
          animationName: p.anim,
          animationDuration: p.duration,
          animationDelay: p.delay,
          animationFillMode: 'forwards',
          animationTimingFunction: 'linear',
        }} />
      ))}
    </div>
  );
}

// ─── Export to window ───────────────────────────────────────────────────────
Object.assign(window, {
  Pip, Card, BulbStrip, Marquee, HUD, Modal, ScoreStrip, CountUp, Confetti,
});
