/*  === monstrance-faith.jsx ===
    Faith subpage scaffold — game shell, sequence/match/reveal games, checkpoint, ExplainerModal, FaithStopPage.
    Loaded as <script type="text/babel" src="js/monstrance-faith.jsx"></script>.
    Cross-file references work because babel-standalone evaluates each script in
    the document's global scope after compile; top-level const/let/function decls
    are visible to subsequent scripts loaded in this order.
*/

const { useState, useEffect, useRef, useCallback } = React;

function FaithGameShell({
  title,
  prompt,
  hints,
  coach,
  progress,
  total,
  success,
  feedback,
  children,
}) {
  const done = progress >= total;
  const hintList = Array.isArray(hints) ? hints : hints ? [hints] : [];
  const [hintLevel, setHintLevel] = React.useState(0);
  const canShowMore = hintLevel < hintList.length;
  return (
    <div className="faith-game">
      <div className="quest-ribbon">
        <span className="quest-badge">
          <span aria-hidden="true">✦</span> Mission
        </span>
        <span className="quest-badge">Guide: {coach}</span>
        <span className="quest-badge">
          {progress}/{total}
        </span>
      </div>
      <h3>{title}</h3>
      <p className="stop-copy">{prompt}</p>
      <div
        className="mini-progress"
        aria-label={`${progress} of ${total} complete`}
      >
        {Array.from({ length: total }).map((_, i) => (
          <span key={i} className={i < progress ? "is-on" : ""} />
        ))}
      </div>
      {children}
      {feedback && (
        <div className="activity-note" aria-live="polite">
          {feedback}
        </div>
      )}
      {!done && hintList.length > 0 && (
        <div className="hint-zone">
          {hintLevel === 0 ? (
            <button
              type="button"
              className="hint-button"
              onClick={() => setHintLevel(1)}
              aria-label="Show a hint"
            >
              <span aria-hidden="true">💡</span> Need a hint?
            </button>
          ) : (
            <React.Fragment>
              <div className="hint-reveal" aria-live="polite">
                <span className="hint-label">Tip from {coach}:</span>{" "}
                {hintList.slice(0, hintLevel).join("  →  ")}
              </div>
              {canShowMore && (
                <button
                  type="button"
                  className="hint-button hint-button-secondary"
                  onClick={() => setHintLevel(hintLevel + 1)}
                >
                  Another hint?
                </button>
              )}
            </React.Fragment>
          )}
        </div>
      )}
      {done && (
        <div className="activity-note is-success" aria-live="polite">
          <strong>{success}</strong>
        </div>
      )}
    </div>
  );
}

function SequenceGame({ stop, game }) {
  const items = game.items;
  const [placed, setPlaced] = React.useState([]);
  const [wrong, setWrong] = React.useState(null);
  const [feedback, setFeedback] = React.useState("");
  const next = placed.length;
  const tap = (idx) => {
    if (placed.includes(idx)) return;
    if (idx === next) {
      setPlaced([...placed, idx]);
      setFeedback(items[idx].teach);
      setWrong(null);
    } else {
      setWrong(idx);
      setFeedback("Hmm, that one comes a little later. Try another.");
      setTimeout(() => setWrong(null), 500);
    }
  };
  const reset = () => {
    setPlaced([]);
    setWrong(null);
    setFeedback("");
  };
  return (
    <FaithGameShell
      title={game.title}
      prompt={game.prompt}
      hints={game.hints || `Look for the very first step: ${items[0].label}.`}
      coach={stop.guide.name}
      progress={placed.length}
      total={items.length}
      success={game.success}
      feedback={feedback}
    >
      <div className="seq-track" aria-label="Mass in order">
        {items.map((_, i) => {
          const filled = i < placed.length;
          const card = filled ? items[placed[i]] : null;
          return (
            <div
              key={i}
              className={`seq-slot ${filled ? "is-filled" : ""} ${i === next ? "is-next" : ""}`}
            >
              <span className="seq-num">{i + 1}</span>
              {filled && (
                <React.Fragment>
                  <img
                    src={`${stop.imgDir}/${card.img}?v=2`}
                    alt=""
                    loading="lazy"
                  />
                  <span className="seq-label">{card.label}</span>
                </React.Fragment>
              )}
            </div>
          );
        })}
      </div>
      <div className="seq-deck" aria-label="Cards left to place">
        {items.map((item, i) =>
          placed.includes(i) ? null : (
            <button
              key={i}
              className={`seq-card ${wrong === i ? "is-wrong" : ""}`}
              onClick={() => tap(i)}
              aria-label={`Place ${item.label}`}
            >
              <img
                src={`${stop.imgDir}/${item.img}?v=2`}
                alt=""
                loading="lazy"
              />
              <div className="seq-card-text">
                <strong>{item.label}</strong>
                <span>{item.sub}</span>
              </div>
            </button>
          ),
        )}
      </div>
      {placed.length > 0 && (
        <div className="game-reset">
          <button className="btn btn-secondary" onClick={reset}>
            Start over
          </button>
        </div>
      )}
    </FaithGameShell>
  );
}

function MatchGame({ stop, game }) {
  const allItems = game.items;
  const phases = game.phases;
  const [phaseIdx, setPhaseIdx] = React.useState(0);
  const [matched, setMatched] = React.useState([]);
  const [picked, setPicked] = React.useState(null);
  const [shake, setShake] = React.useState(null);
  const [feedback, setFeedback] = React.useState("");
  const [shuffleNonce, setShuffleNonce] = React.useState(0);

  const currentPhase = phases ? phases[phaseIdx] : null;
  const items = currentPhase
    ? allItems.filter((it) => currentPhase.itemIds.includes(it.id))
    : allItems;

  const rightOrder = React.useMemo(() => {
    const arr = items.map((_, i) => i);
    for (let i = arr.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    return arr;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [phaseIdx, shuffleNonce, items.length]);

  React.useEffect(() => {
    setMatched([]);
    setPicked(null);
    setShake(null);
    setFeedback("");
  }, [phaseIdx]);

  const tapLeft = (id) => {
    if (matched.includes(id)) return;
    setPicked(id);
    setFeedback("");
  };
  const tapRight = (id) => {
    if (matched.includes(id)) return;
    if (!picked) {
      setFeedback("Tap a symbol on the left first.");
      return;
    }
    if (picked === id) {
      const item = items.find((it) => it.id === id);
      setMatched([...matched, id]);
      setFeedback(item.teach);
      setPicked(null);
    } else {
      setShake(id);
      setFeedback("Not a match yet. Try again, no worries.");
      setTimeout(() => setShake(null), 500);
      setPicked(null);
    }
  };
  const reset = () => {
    setMatched([]);
    setPicked(null);
    setShake(null);
    setFeedback("");
    setShuffleNonce((n) => n + 1);
  };
  const advance = () => setPhaseIdx(phaseIdx + 1);

  const total = allItems.length;
  const itemsBeforePhase = phases
    ? phases.slice(0, phaseIdx).reduce((sum, p) => sum + p.itemIds.length, 0)
    : 0;
  const progress = itemsBeforePhase + matched.length;
  const phaseComplete = items.length > 0 && matched.length === items.length;
  const hasNextPhase = phases && phaseIdx < phases.length - 1;

  return (
    <FaithGameShell
      title={game.title}
      prompt={game.prompt}
      hints={
        game.hints ||
        "Symbols on the left show what we can SEE. Names on the right are the gifts."
      }
      coach={stop.guide.name}
      progress={progress}
      total={total}
      success={game.success}
      feedback={feedback}
    >
      {currentPhase && (
        <div className="phase-head">
          <div className="phase-head-text">
            <h4>{currentPhase.title}</h4>
            <p>{currentPhase.blurb}</p>
          </div>
          <span className="phase-counter">
            Phase {phaseIdx + 1} of {phases.length}
          </span>
        </div>
      )}
      <div className="match-grid">
        <div className="match-col" aria-label="Symbols">
          <div className="match-col-head">Symbols</div>
          {items.map((item) => (
            <button
              key={item.id}
              className={`match-tile ${picked === item.id ? "is-picked" : ""} ${matched.includes(item.id) ? "is-done" : ""}`}
              onClick={() => tapLeft(item.id)}
              disabled={matched.includes(item.id)}
            >
              <span className="match-emoji" aria-hidden="true">
                {item.symbolEmoji}
              </span>
              <span className="match-text">{item.symbolName}</span>
            </button>
          ))}
        </div>
        <div className="match-col" aria-label="Names">
          <div className="match-col-head">Names</div>
          {rightOrder.map((idx) => {
            const item = items[idx];
            if (!item) return null;
            return (
              <button
                key={item.id}
                className={`match-tile is-right ${shake === item.id ? "is-wrong" : ""} ${matched.includes(item.id) ? "is-done" : ""}`}
                onClick={() => tapRight(item.id)}
                disabled={matched.includes(item.id)}
              >
                {matched.includes(item.id) ? (
                  <img
                    src={`${stop.imgDir}/${item.img}?v=2`}
                    alt=""
                    loading="lazy"
                    className="match-thumb"
                  />
                ) : (
                  <span className="match-emoji" aria-hidden="true">
                    ?
                  </span>
                )}
                <span className="match-text">
                  <strong>{item.label}</strong>
                  <em>{item.sub}</em>
                </span>
              </button>
            );
          })}
        </div>
      </div>
      {phaseComplete && hasNextPhase && (
        <div className="game-advance">
          <button className="btn btn-primary" onClick={advance}>
            Next phase →
          </button>
        </div>
      )}
      {matched.length > 0 && !phaseComplete && (
        <div className="game-reset">
          <button className="btn btn-secondary" onClick={reset}>
            Shuffle &amp; retry
          </button>
        </div>
      )}
    </FaithGameShell>
  );
}

function RevealGame({ stop, game }) {
  const items = game.items;
  const [revealed, setRevealed] = React.useState([]);
  const [focused, setFocused] = React.useState(null);
  const tap = (id) => {
    if (!revealed.includes(id)) setRevealed([...revealed, id]);
    setFocused(id);
  };
  const reset = () => {
    setRevealed([]);
    setFocused(null);
  };
  const focusItem = focused ? items.find((it) => it.id === focused) : null;
  return (
    <FaithGameShell
      title={game.title}
      prompt={game.prompt}
      hints={game.hints || "Tap any portrait. Try them in any order."}
      coach={stop.guide.name}
      progress={revealed.length}
      total={items.length}
      success={game.success}
      feedback={focusItem ? focusItem.teach : ""}
    >
      <div className="reveal-grid">
        {items.map((item) => {
          const isOpen = revealed.includes(item.id);
          const isFocus = focused === item.id;
          return (
            <button
              key={item.id}
              className={`reveal-card-game ${isOpen ? "is-open" : ""} ${isFocus ? "is-focus" : ""}`}
              onClick={() => tap(item.id)}
              aria-label={`Reveal ${item.label}`}
            >
              {isOpen ? (
                <React.Fragment>
                  <img
                    className="zoomable"
                    src={`${stop.imgDir}/${item.img}?v=2`}
                    alt={item.label}
                    loading="lazy"
                  />
                  <div className="reveal-text">
                    <strong>{item.label}</strong>
                    <span>{item.sub}</span>
                  </div>
                </React.Fragment>
              ) : (
                <div className="reveal-cover">
                  <span aria-hidden="true">?</span>
                  <span className="reveal-cover-label">{item.label}</span>
                </div>
              )}
            </button>
          );
        })}
      </div>
      {revealed.length > 0 && (
        <div className="game-reset">
          <button className="btn btn-secondary" onClick={reset}>
            Hide all again
          </button>
        </div>
      )}
    </FaithGameShell>
  );
}

function FaithCheckpoint({ checkpoint }) {
  const [opened, setOpened] = React.useState([]);
  const [bloomed, setBloomed] = React.useState(false);
  const open = (i) => {
    if (!opened.includes(i)) setOpened((prev) => [...prev, i]);
    if (checkpoint.choices[i].correct) setBloomed(true);
  };
  const reset = () => {
    setOpened([]);
    setBloomed(false);
  };
  return (
    <div className={`checkpoint discovery ${bloomed ? "is-bloomed" : ""}`}>
      <div className="checkpoint-head">
        <span className="checkpoint-badge" aria-hidden="true">
          {bloomed ? "✦" : "?"}
        </span>
        <h4>{checkpoint.q}</h4>
      </div>
      <p className="checkpoint-hint">
        Tap each card to peek inside. The true one blooms a sparkle.
      </p>
      <div className="checkpoint-options">
        {checkpoint.choices.map((c, i) => {
          const isOpen = opened.includes(i);
          return (
            <button
              key={i}
              className={`checkpoint-choice ${isOpen ? "is-open" : ""} ${isOpen && c.correct ? "is-bloom" : ""}`}
              onClick={() => open(i)}
              aria-pressed={isOpen}
            >
              <span className="checkpoint-face">
                {isOpen ? (
                  <React.Fragment>
                    <span className="checkpoint-mark" aria-hidden="true">
                      {c.correct ? "✦" : "✿"}
                    </span>
                    <span className="checkpoint-text">{c.text}</span>
                    <span className="checkpoint-feedback-inline">
                      {c.feedback}
                    </span>
                  </React.Fragment>
                ) : (
                  <React.Fragment>
                    <span className="checkpoint-mark" aria-hidden="true">
                      ✦
                    </span>
                    <span className="checkpoint-text">{c.text}</span>
                    <span className="checkpoint-feedback-inline">
                      Tap to peek.
                    </span>
                  </React.Fragment>
                )}
              </span>
            </button>
          );
        })}
      </div>
      {bloomed && (
        <div className="checkpoint-bloom" aria-live="polite">
          <span aria-hidden="true">🌼</span> You found the true one.{" "}
          {checkpoint.bloom || "Your faith garden grew a little."}
        </div>
      )}
      {opened.length > 0 && (
        <div className="game-reset">
          <button className="btn btn-secondary" onClick={reset}>
            Close the cards
          </button>
        </div>
      )}
    </div>
  );
}

function FaithGame({ stop }) {
  const game = stop.game;
  if (!game) return null;
  if (game.kind === "sequence") return <SequenceGame stop={stop} game={game} />;
  if (game.kind === "match") return <MatchGame stop={stop} game={game} />;
  return <RevealGame stop={stop} game={game} />;
}

function ExplainerModal({ item, onClose }) {
  useEffect(() => {
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", h);
      document.body.style.overflow = "";
    };
  }, [onClose]);
  const hasText = item.title || item.body || item.sub || item.verse;
  return (
    <div className="lightbox-scrim" onClick={onClose} role="dialog" aria-label={item.title || "Image"}>
      <div className={`explainer-frame ${hasText ? "has-text" : ""}`} onClick={(e) => e.stopPropagation()}>
        <button className="lightbox-close" onClick={onClose} aria-label="Close">×</button>
        <div className="explainer-media">
          <img src={item.src} alt={item.title || ""} />
        </div>
        {hasText && (
          <div className="explainer-body">
            {item.eyebrow && <div className="explainer-eyebrow">{item.eyebrow}</div>}
            {item.title && <h3 className="explainer-title">{item.title}</h3>}
            {item.sub && <div className="explainer-sub">{item.sub}</div>}
            {item.body && <p className="explainer-text">{item.body}</p>}
            {item.verse && <div className="explainer-verse">{item.verse}</div>}
            {item.coPlay && (
              <div className="explainer-coplay">
                <strong>Talk together</strong>
                <span>{item.coPlay}</span>
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

function FaithStopPage({ stop, palette, onCyclePalette, speak, stopSpeech, onShowAudioSetup }) {
  const totalStops = FAITH_STOPS.length;
  const stopIndex = FAITH_STOPS.findIndex(s => s.slug === stop.slug);
  const prev = stopIndex > 0 ? FAITH_STOPS[stopIndex - 1] : null;
  const nextStop = stopIndex < totalStops - 1 ? FAITH_STOPS[stopIndex + 1] : null;
  const [explainer, setExplainer] = useState(null);
  const audioSrc = audioForFaithStop(stop);
  const narration = narrationForFaithStop(stop);
  const listen = () => {
    if (speak) speak(narration, { force: true, audioSrc });
  };
  useEffect(() => () => { if (stopSpeech) stopSpeech(); }, [stop.slug]);
  const openHero = () => setExplainer({
    src: `${stop.imgDir}/${stop.hero}?v=2`,
    eyebrow: `Faith Journey · Stop ${stop.num} of 9`,
    title: stop.title,
    sub: stop.summary,
    body: stop.bigIdea,
  });
  const openGuide = () => setExplainer({
    src: `${stop.imgDir}/${stop.guide.img}?v=2`,
    eyebrow: "Your guide",
    title: stop.guide.name,
    body: stop.guide.line,
  });
  const openTeaching = (t) => setExplainer({
    src: `${stop.imgDir}/${t.img}?v=2`,
    eyebrow: stop.title,
    title: t.title,
    body: t.text,
  });
  return (
    <div className="sky-scene faith-page-bg">
      <CloudComposition showSparkles={true} />
      <div className="stop-page faith-page">
        <TopBar
          readAloud={false}
          onToggleReadAloud={() => {}}
          onShowAudioSetup={() => {}}
          palette={palette}
          onCyclePalette={onCyclePalette}
        />
        <div className="faith-shell">
          <header className="faith-hero">
            <button
              type="button"
              className="faith-hero-art tile-button"
              onClick={openHero}
              aria-label={`Enlarge ${stop.title} illustration`}
            >
              <img
                src={`${stop.imgDir}/${stop.hero}?v=2`}
                alt={`${stop.title} illustration`}
                loading="lazy"
                onError={(e) => {
                  e.currentTarget.style.display = "none";
                }}
              />
            </button>
            <div className="faith-hero-text">
              <div className="stop-kicker">
                Faith Journey · Stop {stop.num} of 9
              </div>
              <h1 className="stop-title">
                <span aria-hidden="true">{stop.icon}</span> {stop.title}
              </h1>
              <p className="stop-copy">{stop.summary}</p>
              <section className="big-idea">
                <div className="big-idea-mark" aria-hidden="true">
                  !
                </div>
                <div>
                  <h3>The big idea</h3>
                  <p className="stop-copy">{stop.bigIdea}</p>
                </div>
              </section>
              <div className="tts-row faith-tts">
                <button className="btn btn-primary" onClick={listen}>
                  <SpeakerIcon on={true} /> Listen to this page
                </button>
                <button className="btn btn-secondary" onClick={stopSpeech}>
                  Stop
                </button>
              </div>
            </div>
          </header>

          <button
            type="button"
            className="guide-bubble tile-button"
            onClick={openGuide}
            aria-label={`More about your guide ${stop.guide.name}`}
          >
            <div className="guide-portrait">
              <img
                src={`${stop.imgDir}/${stop.guide.img}?v=2`}
                alt={`Guide: ${stop.guide.name}`}
                loading="lazy"
                onError={(e) => {
                  e.currentTarget.style.display = "none";
                }}
              />
            </div>
            <div className="guide-speech">
              <div className="guide-name">Your guide: {stop.guide.name}</div>
              <p>{stop.guide.line}</p>
            </div>
            <span className="tile-cue" aria-hidden="true">
              Tap for more
            </span>
          </button>

          <section className="teaching-grid">
            {stop.teachings.map((t, i) => (
              <button
                type="button"
                className="teaching-card has-image tile-button"
                key={i}
                onClick={() => openTeaching(t)}
                aria-label={`Open ${t.title}`}
              >
                <div className="teaching-img">
                  <img
                    src={`${stop.imgDir}/${t.img}?v=2`}
                    alt={t.title}
                    loading="lazy"
                    onError={(e) => {
                      e.currentTarget.style.display = "none";
                    }}
                  />
                </div>
                <div>
                  <h3>{t.title}</h3>
                  <p>{t.text}</p>
                  <span className="tile-cue" aria-hidden="true">
                    Tap for more
                  </span>
                </div>
              </button>
            ))}
          </section>

          <FaithGame stop={stop} />

          <FaithCheckpoint checkpoint={stop.checkpoint} />

          {stop.arcade && (
            <a
              className="arcade-link-card faith-arcade-cta"
              href={stop.arcade.href}
            >
              <span className="arcade-link-icon" aria-hidden="true">
                {stop.arcade.icon}
              </span>
              <span className="arcade-link-copy">
                <strong>{stop.arcade.title}</strong>
                <em>{stop.arcade.blurb}</em>
              </span>
              <span className="arcade-link-tag">Open game →</span>
            </a>
          )}

          <section className="grownup-bridge">
            <div className="bridge-card">
              <strong>Play together</strong>
              <span>{stop.coPlay}</span>
            </div>
            <div className="bridge-card">
              <strong>Bring it off the screen</strong>
              <span>{stop.bridge}</span>
            </div>
          </section>

          <nav className="faith-nav" aria-label="Journey navigation">
            {prev ? (
              <a className="btn btn-secondary" href={`#/faith/${prev.slug}`}>
                ← {prev.title}
              </a>
            ) : (
              <a className="btn btn-secondary" href="#top">
                ← Monstrance home
              </a>
            )}
            <a className="btn btn-secondary" href="#journey">
              All stops
            </a>
            {nextStop ? (
              <a className="btn btn-primary" href={`#/faith/${nextStop.slug}`}>
                {nextStop.title} →
              </a>
            ) : (
              <a className="btn btn-primary" href="#top">
                Back to monstrance
              </a>
            )}
          </nav>
        </div>
      </div>
      {explainer && (
        <ExplainerModal item={explainer} onClose={() => setExplainer(null)} />
      )}
    </div>
  );
}


