/* ============================================================
   SHLOK — The Shlok Deck · Main App
   Card-deck shell with two-card transition engine + swipe
   ============================================================ */
const { useState: uS, useEffect: uE, useRef: uR, useCallback: uC } = React;

function selectionCount(step, data) {
  const value = data[step.key];
  if (Array.isArray(value)) return value.length;
  return value ? 1 : 0;
}

function minRequired(step) {
  if (typeof step.minSelections === "number") return step.minSelections;
  if (step.type === "sliders") return 0;
  return step.type === "welcome" || step.type === "complete" ? 0 : 1;
}

function maxAllowed(step) {
  if (typeof step.maxSelections === "number") return step.maxSelections;
  if (typeof step.max === "number") return step.max;
  return null;
}

function constraintStatus(step, data) {
  const count = selectionCount(step, data);
  const min = minRequired(step);
  const max = maxAllowed(step);
  const valid = count >= min && (max == null || count <= max);
  return { count, min, max, valid };
}

/* ---------- One card's full content (illo + body + foot) ---------- */
function StepCard({ step, data, set, requestAdvance, valid, onNext, isLast, leaving }) {
  const showFoot = !(step.type === "single" && step.autoAdvance);
  return (
    <React.Fragment>
      {step.illo ? (
        <div className="card-illo">
          <window.Illo name={step.illo} />
          <div className="illo-fade" />
        </div>
      ) : null}
      <div className="card-body">
        <window.StepContent step={step} data={data} set={set} requestAdvance={requestAdvance} />
      </div>
      {showFoot ? (
        <div className="card-foot">
          {renderHint(step, data)}
          <span className="spacer" />
          <window.PrimaryBtn disabled={!valid} onClick={onNext} label={isLast ? "Finish" : "Continue"} />
        </div>
      ) : (
        <div className="card-foot">
          {renderHint(step, data)}
          <span className="spacer" />
          <span className="hint" style={{ opacity: 0.7 }}>
            <window.Icon name="touch" size={15} /> tap to choose
          </span>
        </div>
      )}
    </React.Fragment>
  );
}

function renderHint(step, data) {
  const t = step.type;
  const status = constraintStatus(step, data);
  if (!status.valid && status.min > 0) {
    return <span className="hint required">{step.constraintLabel || `Choose at least ${status.min}`}</span>;
  }
  if (t === "rank") {
    return <span className="hint">{status.count} / {status.max || step.max} ranked</span>;
  }
  if (t === "multi" || t === "loss") {
    return <span className="hint">{status.count ? `${status.count} selected` : "Select all that apply"}</span>;
  }
  if (t === "contact" && data[step.key] === "no") {
    return <span className="hint">No problem — we won’t ask</span>;
  }
  return <span className="hint" />;
}

/* ---------- App ---------- */
function App() {
  const STEPS = window.SHLOK.STEPS;
  const TOTAL_Q = window.SHLOK.QUESTION_STEPS;

  const [idx, setIdx] = uS(0);
  const [dir, setDir] = uS(1);
  const [data, setData] = uS({});
  const [debug, setDebug] = uS(false);
  const [leaving, setLeaving] = uS(null);   // { idx, dir }
  const [drag, setDrag] = uS(0);            // current drag offset (px)
  const [dragging, setDragging] = uS(false);

  const advTimer = uR(null);
  const goRef = uR({});
  const animating = uR(false);

  const step = STEPS[idx];

  const set = uC((key, val) => {
    setData((d) => ({ ...d, [key]: typeof val === "function" ? val(d[key]) : val }));
  }, []);

  function clearAdv() { if (advTimer.current) { clearTimeout(advTimer.current); advTimer.current = null; } }

  const go = uC((delta) => {
    if (animating.current) return;
    const next = Math.min(Math.max(idx + delta, 0), STEPS.length - 1);
    if (next === idx) return;
    clearAdv();
    animating.current = true;
    setDir(delta > 0 ? 1 : -1);
    setLeaving({ idx, dir: delta > 0 ? 1 : -1 });
    setIdx(next);
    setDrag(0);
    setDragging(false);
    setTimeout(() => { setLeaving(null); animating.current = false; }, 600);
  }, [idx, STEPS.length]);

  goRef.current = { go };

  function requestAdvance() {
    clearAdv();
    advTimer.current = setTimeout(() => goRef.current.go(1), 340);
  }

  function restart() { clearAdv(); setData({}); setDir(-1); setLeaving(null); animating.current = false; setIdx(0); }

  function isValid(s = step) {
    return constraintStatus(s, data).valid;
  }
  const valid = isValid();
  const isQuestion = step.type !== "welcome" && step.type !== "complete";
  const isLast = idx === STEPS.length - 2;

  // keyboard
  uE(() => {
    function onKey(e) {
      const tag = (e.target.tagName || "").toLowerCase();
      const typing = tag === "input" || tag === "textarea";
      if ((e.key === "d" || e.key === "D") && !typing && !e.metaKey && !e.ctrlKey && !e.altKey) { setDebug((v) => !v); return; }
      if (typing) return;
      if (e.key === "ArrowRight" || e.key === "Enter") {
        if (step.type === "welcome") go(1);
        else if (step.type === "complete") restart();
        else if (valid) go(1);
      }
      if (e.key === "ArrowLeft" && idx > 0) go(-1);
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  });

  // ---- swipe / drag on active card ----
  const dragState = uR(null);
  function onPointerDown(e) {
    if (!isQuestion || animating.current) return;
    // ignore drags starting on interactive controls
    if (e.target.closest("input, textarea, button, .range, .card-body")) {
      // allow drag from illo / card chrome only
      if (!e.target.closest(".card-illo")) return;
    }
    dragState.current = { x: e.clientX, y: e.clientY, decided: false, horiz: false };
  }
  function onPointerMove(e) {
    const st = dragState.current;
    if (!st) return;
    const dx = e.clientX - st.x, dy = e.clientY - st.y;
    if (!st.decided) {
      if (Math.abs(dx) < 8 && Math.abs(dy) < 8) return;
      st.decided = true;
      st.horiz = Math.abs(dx) > Math.abs(dy);
      if (st.horiz) setDragging(true);
    }
    if (st.horiz) { e.preventDefault(); setDrag(dx); }
  }
  function endDrag() {
    const st = dragState.current;
    dragState.current = null;
    if (!st || !st.horiz) { setDrag(0); setDragging(false); return; }
    const threshold = 90;
    if (drag <= -threshold && valid) { go(1); }
    else if (drag >= threshold && idx > 0) { go(-1); }
    else { setDragging(false); setDrag(0); }
  }

  // dynamic transform while dragging the active card
  const dragStyle = dragging && drag !== 0
    ? { transform: `translateX(${drag}px) rotate(${drag * 0.025}deg)`, transition: "none" }
    : (dragging ? { transition: "none" } : null);

  // ---------- RENDER ----------
  const enterClass = isQuestion || step.type === "complete"
    ? (dir === 1 ? "enter-f" : "enter-b") : "enter-f";

  // chrome (only on question steps)
  const progressPct = isQuestion ? Math.round((idx / TOTAL_Q) * 100) : 0;

  const chrome = isQuestion ? (
    <div className="chrome">
      <button className="back" onClick={() => go(-1)} disabled={idx <= 1} aria-label="Go back">
        <window.Icon name="chevronLeft" size={20} />
      </button>
      <div className="seg-wrap">
        <div className="seg-meta">
          <span className="label">SHLOK</span>
          <span className="count"><b>{idx}</b> / {TOTAL_Q}<em>{progressPct}%</em></span>
        </div>
        <div className="segs">
          {Array.from({ length: TOTAL_Q }).map((_, i) => (
            <span key={i} className={"s " + (i + 1 < idx ? "done" : i + 1 === idx ? "cur" : "")}><i /></span>
          ))}
        </div>
      </div>
      <div
        className="brand-dot" role="button" tabIndex={0} aria-label="Shlok" title="Shlok"
        onClick={() => { /* tap = nothing; long-press handled below */ }}
        onContextMenu={(e) => { e.preventDefault(); setDebug((v) => !v); }}
      />
    </div>
  ) : (
    <div className="chrome">
      <span className="seg-wrap" />
      <div className="brand-dot" role="button" tabIndex={0} aria-label="Shlok" onContextMenu={(e) => { e.preventDefault(); setDebug((v) => !v); }} />
    </div>
  );

  return (
    <div className={"app " + (isQuestion ? "in-flow" : "at-edge")}>
      {chrome}
      <div className="deck-viewport">
        <div className="deck">
          {/* depth ghosts (only mid-deck) */}
          {isQuestion ? <div className="ghost g1" /> : null}
          {isQuestion ? <div className="ghost g2" /> : null}

          {/* leaving card */}
          {leaving ? (
            <div className={"card leaving " + (leaving.dir === 1 ? "leave-f" : "leave-b") + (STEPS[leaving.idx].dense ? " dense" : "")}>
              <LeaveContent step={STEPS[leaving.idx]} data={data} />
            </div>
          ) : null}

          {/* active card */}
          <div
            className={"card " + enterClass + (isQuestion ? " grab" : "") + (dragging ? " grabbing" : "") + (step.dense ? " dense" : "")}
            style={dragStyle}
            key={idx}
            onPointerDown={onPointerDown}
            onPointerMove={onPointerMove}
            onPointerUp={endDrag}
            onPointerCancel={endDrag}
            onPointerLeave={() => { if (dragState.current) endDrag(); }}
          >
            {step.type === "welcome" ? (
              <Welcome onStart={() => go(1)} />
            ) : step.type === "complete" ? (
              <Complete data={data} onRestart={restart} />
            ) : (
              <StepCard
                step={step} data={data} set={set} requestAdvance={requestAdvance}
                valid={valid} onNext={() => go(1)} isLast={isLast}
              />
            )}
          </div>
        </div>
      </div>

      {debug ? <DebugPanel data={data} onClose={() => setDebug(false)} /> : null}
      {step.type === "welcome" ? <div className="debug-hintbar">press “d” for research debug panel</div> : null}
    </div>
  );
}

/* leaving card renders a static snapshot (no interaction) */
function LeaveContent({ step, data }) {
  if (step.type === "welcome") return <Welcome onStart={() => {}} />;
  if (step.type === "complete") return <Complete data={data} onRestart={() => {}} />;
  return (
    <React.Fragment>
      {step.illo ? (<div className="card-illo"><window.Illo name={step.illo} /><div className="illo-fade" /></div>) : null}
      <div className="card-body"><window.StepContent step={step} data={data} set={() => {}} requestAdvance={() => {}} /></div>
      <div className="card-foot"><span className="hint" /></div>
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
