// space-memory.jsx
// Space Memory: 4-by-4 flip-card matching game with per-card narration.

const SPACE_MEMORY_ITEMS = [
  {
    id: "sun",
    name: "Sun",
    clue: "Warm star",
    tint: "#ffd66b",
    audio: "memory_sun.mp3",
  },
  {
    id: "mercury",
    name: "Mercury",
    clue: "Closest planet",
    tint: "#b8ad9d",
    audio: "memory_mercury.mp3",
  },
  {
    id: "venus",
    name: "Venus",
    clue: "Cloudy world",
    tint: "#f2b66d",
    audio: "memory_venus.mp3",
  },
  {
    id: "earth",
    name: "Earth",
    clue: "Blue home",
    tint: "#67d6ff",
    audio: "memory_earth.mp3",
  },
  {
    id: "mars",
    name: "Mars",
    clue: "Rusty red",
    tint: "#ff8d62",
    audio: "memory_mars.mp3",
  },
  {
    id: "jupiter",
    name: "Jupiter",
    clue: "Biggest planet",
    tint: "#f6c48c",
    audio: "memory_jupiter.mp3",
  },
  {
    id: "saturn",
    name: "Saturn",
    clue: "Wide rings",
    tint: "#f3dd92",
    audio: "memory_saturn.mp3",
  },
  {
    id: "neptune",
    name: "Neptune",
    clue: "Cold blue",
    tint: "#7ca7ff",
    audio: "memory_neptune.mp3",
  },
];

function createSpaceMemoryDeck() {
  const deck = SPACE_MEMORY_ITEMS.flatMap((item) => [
    { ...item, cardId: `${item.id}-a` },
    { ...item, cardId: `${item.id}-b` },
  ]);
  for (let index = deck.length - 1; index > 0; index -= 1) {
    const swapIndex = Math.floor(Math.random() * (index + 1));
    [deck[index], deck[swapIndex]] = [deck[swapIndex], deck[index]];
  }
  return deck;
}

function SpaceMemoryPlanet({ item }) {
  return (
    <span
      className={`space-memory-world space-memory-world-${item.id}`}
      style={{ "--memory-card-tint": item.tint }}
      title={item.name}
      aria-hidden="true"
    />
  );
}

function SpaceMemoryLevel({ onExit }) {
  const [deck, setDeck] = useState(() => createSpaceMemoryDeck());
  const [flipped, setFlipped] = useState([]);
  const [matched, setMatched] = useState([]);
  const [locked, setLocked] = useState(false);
  const [moves, setMoves] = useState(0);
  const [message, setMessage] = useState("Flip two space cards.");
  const [pulseCards, setPulseCards] = useState([]);
  const timersRef = useRef([]);
  const flippedRef = useRef([]);
  const matchedRef = useRef([]);
  const lockedRef = useRef(false);
  const celebrationShownRef = useRef(false);
  const matchedCount = matched.length / 2;
  const complete = matched.length === deck.length;
  useEscapeHandler(onExit, true);

  const clearTimers = () => {
    timersRef.current.forEach((timer) => window.clearTimeout(timer));
    timersRef.current = [];
  };

  const schedule = (fn, delay) => {
    const timer = window.setTimeout(fn, delay);
    timersRef.current.push(timer);
    return timer;
  };

  useEffect(() => {
    window.scrollTo({ top: 0, left: 0 });
    playNarration("memory_intro.mp3");
    return () => {
      clearTimers();
      stopNarration();
    };
  }, []);

  const reset = () => {
    clearTimers();
    setDeck(createSpaceMemoryDeck());
    flippedRef.current = [];
    matchedRef.current = [];
    lockedRef.current = false;
    setFlipped([]);
    setMatched([]);
    setLocked(false);
    setMoves(0);
    setPulseCards([]);
    setMessage("New board. Flip two space cards.");
    celebrationShownRef.current = false;
    playNarration("memory_intro.mp3");
  };

  const peekAllCards = () => {
    if (lockedRef.current || matchedRef.current.length === deck.length) return;
    clearTimers();
    const unmatchedCards = deck
      .filter((card) => !matchedRef.current.includes(card.cardId))
      .map((card) => card.cardId);
    lockedRef.current = true;
    setLocked(true);
    flippedRef.current = unmatchedCards;
    setFlipped(unmatchedCards);
    setPulseCards([]);
    setMessage("Take a quick look. The cards will hide again.");
    schedule(() => {
      flippedRef.current = [];
      lockedRef.current = false;
      setFlipped([]);
      setLocked(false);
      setMessage("Now try two cards you remember.");
    }, 1400);
  };

  const revealCard = (card) => {
    const currentFlipped = flippedRef.current;
    const currentMatched = matchedRef.current;
    if (lockedRef.current || currentMatched.length === deck.length) return;
    if (
      currentMatched.includes(card.cardId) ||
      currentFlipped.includes(card.cardId)
    ) {
      return;
    }

    playNarration(card.audio);
    const nextFlipped = [...currentFlipped, card.cardId];
    flippedRef.current = nextFlipped;
    setFlipped(nextFlipped);
    setPulseCards([card.cardId]);

    if (nextFlipped.length !== 2) {
      setMessage(`${card.name}. Find its twin.`);
      return;
    }

    const [firstId] = nextFlipped;
    const first = deck.find((item) => item.cardId === firstId);
    setMoves((count) => count + 1);
    lockedRef.current = true;
    setLocked(true);

    if (first && first.id === card.id) {
      const matchedCards = [first.cardId, card.cardId];
      const nextMatched = [...currentMatched, ...matchedCards];
      setPulseCards(matchedCards);
      setMessage(`${card.name} match!`);
      schedule(() => {
        matchedRef.current = nextMatched;
        flippedRef.current = [];
        lockedRef.current = false;
        setMatched(nextMatched);
        setFlipped([]);
        setLocked(false);
        setPulseCards([]);
        playNarration(nextMatched.length === deck.length ? "memory_win.mp3" : "memory_match.mp3");
        if (nextMatched.length === deck.length) {
          setMessage("Mission complete. Every pair is matched.");
          if (!celebrationShownRef.current) {
            celebrationShownRef.current = true;
            window.SpaceExplorerFoundation?.celebrateGameFinish?.({
              gameId: "space-memory",
              emoji: "▦",
              title: "All pairs found!",
              message: "You remembered every space card.",
            });
          }
        } else {
          setMessage("Good match. Flip two more cards.");
        }
      }, 850);
      return;
    }

    setMessage("Not a match yet. Watch them flip back.");
    playKidSound("pop");
    schedule(() => playNarration("memory_try_again.mp3"), 780);
    schedule(() => {
      flippedRef.current = [];
      lockedRef.current = false;
      setFlipped([]);
      setLocked(false);
      setPulseCards([]);
      setMessage("Try again. You saw where they hide.");
    }, 1450);
  };

  return (
    <section className="space-memory-level" aria-label="Space Memory game">
      <Starfield count={240} />
      <button className="planet-sort-back" onClick={onExit}>
        ← Back to planets
      </button>
      <div className="space-memory-shell">
        <div className="space-memory-copy">
          <span>Space Memory</span>
          <h1>{complete ? "All pairs found!" : "Flip two cards"}</h1>
          <p>
            Match the space pictures. A card that does not match flips back over.
          </p>
          <div className="space-memory-status" role="status" aria-live="polite">
            <strong>{message}</strong>
            <small>
              {matchedCount} of {SPACE_MEMORY_ITEMS.length} pairs · {moves} tries
            </small>
          </div>
          <div className="space-memory-actions">
            <button onClick={reset}>New board</button>
            {!complete ? <button onClick={peekAllCards}>Peek</button> : null}
            {complete ? <button onClick={onExit}>Done</button> : null}
          </div>
        </div>
        <div className="space-memory-board" aria-label="4 by 4 memory cards">
          {deck.map((card, index) => {
            const isMatched = matched.includes(card.cardId);
            const isFlipped = flipped.includes(card.cardId) || isMatched;
            const isPulsing = pulseCards.includes(card.cardId);
            return (
              <button
                key={card.cardId}
                className={[
                  "space-memory-card",
                  isFlipped ? "flipped" : "",
                  isMatched ? "matched" : "",
                  isPulsing ? "pulse" : "",
                ]
                  .filter(Boolean)
                  .join(" ")}
                style={{ "--memory-card-tint": card.tint }}
                data-card-id={card.cardId}
                data-match-id={card.id}
                onClick={() => revealCard(card)}
                disabled={locked || isMatched}
                aria-label={
                  isFlipped
                    ? `${card.name}. ${card.clue}.`
                    : `Hidden space card ${index + 1}`
                }
              >
                <span className="space-memory-card-inner">
                  <span className="space-memory-card-face space-memory-card-back">
                    <span className="space-memory-card-orbit" aria-hidden="true" />
                    <strong>?</strong>
                  </span>
                  <span className="space-memory-card-face space-memory-card-front">
                    <SpaceMemoryPlanet item={card} />
                    <strong>{card.name}</strong>
                    <small>{card.clue}</small>
                  </span>
                </span>
              </button>
            );
          })}
        </div>
      </div>
    </section>
  );
}

window.SpaceExplorerMemoryGame = {
  items: SPACE_MEMORY_ITEMS,
  createDeck: createSpaceMemoryDeck,
};
