// constructor.jsx — team photo nickname constructor
const { useState, useRef, useEffect: useEffectC } = React;

/* Character anchor positions over team-photo.jpg
   x, y are in % of image. Labels are centered on x and float above (y).
   Heights are staggered so neighbouring labels never collide or cover faces. */
const ANCHORS = [
  { id: 1, x: 44.0, y: 35.4 },  // woman, headband, aiming AK
  { id: 2, x: 49.5, y: 51.4 },  // crouching masked (front)
  { id: 3, x: 55.0, y: 30.9 },  // masked, AK raised (back)  — down 20px
  { id: 4, x: 58.5, y: 37.4 },  // astronaut centerpiece
  { id: 5, x: 68.5, y: 29.4 },  // tall riot-helmet
  { id: 6, x: 80.3, y: 51.4 },  // kneeling helmet, AK
  { id: 7, x: 81.8, y: 33.4 },  // shirtless, suspenders (back)
  { id: 8, x: 85.3, y: 47.9 },  // kneeling gas-mask (front)
  { id: 9, x: 90.7, y: 37.7 },  // far right, masked AK
];

const PRESET_NAMES = [
  "VOLK", "GHOST", "RUST", "ASTRO",
  "TANK", "BLADE", "WIRE", "SCRAP", "HEX"
];

const TITLE_STYLES = [
  { key: "ember",   label: "Ember" },
  { key: "chrome",  label: "Chrome" },
  { key: "toxic",   label: "Toxic" },
  { key: "stencil", label: "Stencil" },
];

function Constructor() {
  const [names, setNames] = useState(() => ANCHORS.map(() => ""));
  const [disabled, setDisabled] = useState(() => new Set());
  const [clanTitle, setClanTitle] = useState("");
  const [titleStyle, setTitleStyle] = useState("ember");
  const [titleOn, setTitleOn] = useState(true);
  const [toast, setToast] = useState(null);
  const stageRef = useRef(null);
  const imgRef = useRef(null);
  const titleRef = useRef(null);

  // Scale label sizes proportional to stage width
  useEffectC(() => {
    const el = stageRef.current;
    if (!el) return;
    const update = () => {
      const w = el.offsetWidth;
      const s = Math.max(0.55, Math.min(1.15, w / 1440));
      el.style.setProperty("--s", s);
    };
    update();
    const ro = new ResizeObserver(update);
    ro.observe(el);
    window.addEventListener("resize", update);
    return () => { ro.disconnect(); window.removeEventListener("resize", update); };
  }, []);

  const setName = (i, v) => {
    const next = names.slice();
    next[i] = v.toUpperCase().slice(0, 14);
    setNames(next);
  };

  const removeRow = (id) => {
    const next = new Set(disabled);
    next.add(id);
    setDisabled(next);
  };
  const restoreRow = (id) => {
    const next = new Set(disabled);
    next.delete(id);
    setDisabled(next);
  };

  const fillPresets = () => {
    setNames(PRESET_NAMES.slice(0, ANCHORS.length));
  };
  const clearAll = () => setNames(ANCHORS.map(() => ""));
  const resetDefaults = () => {
    setNames(ANCHORS.map(() => ""));
    setDisabled(new Set());
    setClanTitle("");
    setTitleStyle("ember");
    setTitleOn(true);
    if (titleRef.current) titleRef.current.textContent = "";
  };

  const setTitleFromPanel = (v) => {
    const val = v.slice(0, 18);
    setClanTitle(val);
    if (titleRef.current && titleRef.current.textContent !== val) {
      titleRef.current.textContent = val;
    }
  };

  const showToast = (msg) => {
    setToast(msg);
    setTimeout(() => setToast(null), 1800);
  };

  const handleDownload = async () => {
    const img = imgRef.current;
    if (!img || !img.complete) {
      showToast("Loading...");
      return;
    }
    if (document.fonts && document.fonts.ready) {
      try { await document.fonts.ready; } catch (e) {}
    }
    const w = img.naturalWidth;
    const h = img.naturalHeight;
    const canvas = document.createElement("canvas");
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, w, h);

    const fontSize = Math.round(h * 0.032);
    ctx.font = `700 ${fontSize}px "Space Grotesk", system-ui, sans-serif`;
    ctx.textBaseline = "middle";
    const dotR = fontSize * 0.36;
    const gap = fontSize * 0.5;
    const padX = fontSize * 0.5;
    const padY = fontSize * 0.32;

    ANCHORS.forEach((a, i) => {
      if (disabled.has(a.id)) return;
      const text = names[i];
      if (!text) return;
      const tw = ctx.measureText(text).width;
      const blockW = dotR * 2 + gap + tw + padX * 2;
      const blockH = fontSize + padY * 2;
      const cx = (a.x / 100) * w;
      const cy = (a.y / 100) * h;
      const x0 = cx - blockW / 2;
      const y0 = cy;

      ctx.fillStyle = "rgba(11,12,13,0.65)";
      roundRect(ctx, x0, y0, blockW, blockH, 4);
      ctx.fill();
      ctx.strokeStyle = "rgba(110,255,58,0.75)";
      ctx.lineWidth = Math.max(1, fontSize * 0.06);
      roundRect(ctx, x0, y0, blockW, blockH, 4);
      ctx.stroke();

      const dotCx = x0 + padX + dotR;
      const dotCy = y0 + blockH / 2;
      const glow = ctx.createRadialGradient(dotCx, dotCy, 0, dotCx, dotCy, dotR * 3);
      glow.addColorStop(0, "rgba(110,255,58,0.7)");
      glow.addColorStop(1, "rgba(110,255,58,0)");
      ctx.fillStyle = glow;
      ctx.beginPath();
      ctx.arc(dotCx, dotCy, dotR * 3, 0, Math.PI * 2);
      ctx.fill();
      ctx.fillStyle = "#6EFF3A";
      ctx.beginPath();
      ctx.arc(dotCx, dotCy, dotR, 0, Math.PI * 2);
      ctx.fill();

      ctx.save();
      ctx.fillStyle = "#9EFF6B";
      ctx.shadowColor = "rgba(110,255,58,0.85)";
      ctx.shadowBlur = fontSize * 0.6;
      ctx.fillText(text, dotCx + dotR + gap, dotCy);
      ctx.restore();
    });

    ctx.font = `500 ${Math.round(h * 0.014)}px "JetBrains Mono", monospace`;
    ctx.fillStyle = "rgba(255,255,255,0.45)";
    ctx.fillText("OXIDE · TEAM", w * 0.018, h * 0.96);

    if (titleOn && clanTitle.trim()) {
      drawClanTitle(ctx, clanTitle.trim(), w, h, titleStyle);
    }

    canvas.toBlob((blob) => {
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      const stamp = new Date().toISOString().slice(0, 10);
      a.download = `oxide-team-${stamp}.png`;
      a.click();
      setTimeout(() => URL.revokeObjectURL(url), 1000);
      showToast("Downloaded");
    }, "image/png");
  };

  const activeAnchors = ANCHORS.filter((a) => !disabled.has(a.id));
  const filledCount = activeAnchors.filter((a) => names[ANCHORS.indexOf(a)]).length;
  const totalActive = activeAnchors.length;

  return (
    <div>
      <div className="page-head">
        <div>
          <h1>TEAM <span className="h1-accent">/</span> CONSTRUCTOR</h1>
          <p className="page-sub">Type in your friends' names and make a team photo.</p>
        </div>
        <p>Enter nicknames above each fighter and save your clan's team photo.</p>
      </div>

      <div className="filterbar">
        <span className="label">PROGRESS</span>
        <span className="mono" style={{color: filledCount === totalActive && totalActive > 0 ? "var(--friend)" : "var(--fg)"}}>
          {filledCount.toString().padStart(2, "0")} / {totalActive.toString().padStart(2, "0")}
        </span>
        {disabled.size > 0 && (
          <>
            <span className="label" style={{marginLeft: 16}}>HIDDEN</span>
            <span className="mono" style={{color: "var(--fg-mute)"}}>{disabled.size.toString().padStart(2, "0")}</span>
          </>
        )}
        <div className="spacer"></div>
        <span className="sort">RESOLUTION&nbsp;<span>3168 × 1344</span></span>
      </div>

      <div className="constructor-wrap">
        <div className="stage-frame" ref={stageRef}>
          <img
            ref={imgRef}
            className="stage-bg"
            src="assets/team-photo.jpg"
            alt="Team photo"
            crossOrigin="anonymous"
          />

          <div className={"clan-title-wrap" + (titleOn ? "" : " hidden")}>
            <div
              className={"clan-title style-" + titleStyle}
              contentEditable
              suppressContentEditableWarning
              ref={titleRef}
              data-placeholder="CLAN NAME"
              spellCheck={false}
              onInput={(e) => setClanTitle(e.currentTarget.textContent.slice(0, 18))}
            ></div>
            <button
              className="title-remove"
              title="Remove title"
              onClick={() => setTitleOn(false)}
              aria-label="remove title"
            >×</button>
          </div>
          {ANCHORS.map((a, i) => {
            if (disabled.has(a.id)) return null;
            return (
              <div
                key={a.id}
                className="tag-input"
                style={{
                  left: a.x + "%",
                  top: a.y + "%",
                  transform: "translate(-50%, 0)",
                }}
              >
                <span className="tag-dot"></span>
                <input
                  className="tag-field"
                  type="text"
                  maxLength={14}
                  placeholder={"P" + a.id.toString().padStart(2, "0")}
                  value={names[i]}
                  onChange={(e) => setName(i, e.target.value)}
                />
                <button
                  className="tag-remove"
                  title="Remove this slot"
                  onClick={() => removeRow(a.id)}
                  aria-label="remove"
                >×</button>
              </div>
            );
          })}
        </div>

        <aside className="panel">
          <h3>Constructor</h3>
          <div className="panel-sub">Steps · 003</div>

          <div className="step"><span className="n">01</span>Click the field above a fighter and type a nickname.</div>
          <div className="step"><span className="n">02</span>Up to 14 characters. Uppercase only.</div>
          <div className="step"><span className="n">03</span>Hit “Download” — PNG at original resolution.</div>

          <div className="title-section">
            <div className="ts-head">
              <span className="ts-label">CLAN TITLE</span>
              {titleOn ? (
                <button className="ts-toggle" onClick={() => setTitleOn(false)}>Remove</button>
              ) : (
                <button className="ts-toggle add" onClick={() => setTitleOn(true)}>+ Add title</button>
              )}
            </div>
            {titleOn && (
              <>
                <input
                  className="ts-input"
                  type="text"
                  placeholder="Type clan name…"
                  value={clanTitle}
                  maxLength={18}
                  onChange={(e) => setTitleFromPanel(e.target.value)}
                />
                <div className="ts-styles">
                  {TITLE_STYLES.map((s) => (
                    <button
                      key={s.key}
                      className={"ts-style style-" + s.key + (titleStyle === s.key ? " active" : "")}
                      onClick={() => setTitleStyle(s.key)}
                    >
                      <span className="ts-style-preview">Aa</span>
                      <span className="ts-style-name">{s.label}</span>
                    </button>
                  ))}
                </div>
              </>
            )}
          </div>

          <div className="field-list">
            {ANCHORS.map((a, i) => {
              const isOff = disabled.has(a.id);
              return (
                <div className={"field-row " + (isOff ? "off" : "")} key={a.id}>
                  <span className="idx mono">{a.id.toString().padStart(2, "0")}</span>
                  <span className="row-dot"></span>
                  <input
                    type="text"
                    placeholder={"PLAYER " + a.id.toString().padStart(2, "0")}
                    value={names[i]}
                    maxLength={14}
                    onChange={(e) => setName(i, e.target.value)}
                    disabled={isOff}
                  />
                  {isOff ? (
                    <button
                      className="row-btn restore"
                      title="Restore slot"
                      onClick={() => restoreRow(a.id)}
                      aria-label="restore"
                    >+</button>
                  ) : (
                    <button
                      className="row-btn remove"
                      title="Remove slot"
                      onClick={() => removeRow(a.id)}
                      aria-label="remove"
                    >×</button>
                  )}
                </div>
              );
            })}
          </div>

          <div className="actions">
            <button onClick={handleDownload}>
              <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.6">
                <path d="M6 1v8M2 6l4 4 4-4M1 11h10" />
              </svg>
              Download PNG
            </button>
            <button className="ghost" onClick={fillPresets}>Fill with example</button>
            <button className="ghost" onClick={clearAll}>Clear names</button>
            <button className="ghost" onClick={resetDefaults}>Reset to defaults</button>
          </div>
        </aside>
      </div>

      {toast && <div className="toast">{toast}</div>}
    </div>
  );
}

function roundRect(ctx, x, y, w, h, r) {
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.quadraticCurveTo(x + w, y, x + w, y + r);
  ctx.lineTo(x + w, y + h - r);
  ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
  ctx.lineTo(x + r, y + h);
  ctx.quadraticCurveTo(x, y + h, x, y + h - r);
  ctx.lineTo(x, y + r);
  ctx.quadraticCurveTo(x, y, x + r, y);
  ctx.closePath();
}

/* Draws the clan banner title at top-center of the canvas, matching the 4 CSS styles. */
function drawClanTitle(ctx, text, w, h, style) {
  text = text.toUpperCase();
  const fontSize = Math.round(h * 0.072);
  const cx = w / 2;
  const topY = h * 0.045;

  ctx.save();
  ctx.textAlign = "center";
  ctx.textBaseline = "top";
  const fam = style === "stencil" ? '"Black Ops One", system-ui' : '"Anton", system-ui';
  ctx.font = `${fontSize}px ${fam}`;
  if ("letterSpacing" in ctx) {
    ctx.letterSpacing = style === "stencil" ? `${fontSize * 0.08}px` : `${fontSize * 0.02}px`;
  }

  const grad = ctx.createLinearGradient(0, topY, 0, topY + fontSize);

  if (style === "ember") {
    grad.addColorStop(0, "#ffe0ad");
    grad.addColorStop(0.5, "#ff7a45");
    grad.addColorStop(1, "#d8401c");
    ctx.lineWidth = fontSize * 0.08;
    ctx.strokeStyle = "rgba(20,8,4,0.9)";
    ctx.shadowColor = "rgba(0,0,0,0.55)";
    ctx.shadowBlur = fontSize * 0.12;
    ctx.shadowOffsetY = fontSize * 0.04;
    ctx.strokeText(text, cx, topY);
    ctx.shadowColor = "rgba(233,75,48,0.7)";
    ctx.shadowBlur = fontSize * 0.5;
    ctx.shadowOffsetY = 0;
    ctx.fillStyle = grad;
    ctx.fillText(text, cx, topY);
  } else if (style === "chrome") {
    grad.addColorStop(0, "#ffffff");
    grad.addColorStop(0.45, "#aab2bb");
    grad.addColorStop(0.55, "#4c535b");
    grad.addColorStop(1, "#dfe6ec");
    ctx.lineWidth = fontSize * 0.1;
    ctx.strokeStyle = "#0c0e11";
    ctx.shadowColor = "rgba(0,0,0,0.6)";
    ctx.shadowBlur = fontSize * 0.12;
    ctx.shadowOffsetY = fontSize * 0.04;
    ctx.strokeText(text, cx, topY);
    ctx.shadowColor = "rgba(0,0,0,0)";
    ctx.shadowBlur = 0;
    ctx.shadowOffsetY = 0;
    ctx.fillStyle = grad;
    ctx.fillText(text, cx, topY);
  } else if (style === "toxic") {
    ctx.lineWidth = fontSize * 0.06;
    ctx.strokeStyle = "rgba(8,20,4,0.9)";
    ctx.shadowColor = "rgba(110,255,58,0.9)";
    ctx.shadowBlur = fontSize * 0.6;
    ctx.fillStyle = "#9EFF6B";
    ctx.fillText(text, cx, topY);
    ctx.shadowBlur = 0;
    ctx.strokeText(text, cx, topY);
    ctx.fillStyle = "#cfffb0";
    ctx.fillText(text, cx, topY);
  } else {
    // stencil
    ctx.lineWidth = fontSize * 0.12;
    ctx.strokeStyle = "#14120d";
    ctx.shadowColor = "rgba(0,0,0,0.5)";
    ctx.shadowBlur = fontSize * 0.1;
    ctx.shadowOffsetY = fontSize * 0.03;
    ctx.strokeText(text, cx, topY);
    ctx.shadowBlur = 0;
    ctx.shadowOffsetY = 0;
    ctx.fillStyle = "#ece6d8";
    ctx.fillText(text, cx, topY);
  }

  if ("letterSpacing" in ctx) ctx.letterSpacing = "0px";
  ctx.restore();
}

window.Constructor = Constructor;
