// control-board-memory.jsx
// Control Board Memory: repeat glowing ship-button patterns with sound clues.

const CONTROL_BOARD_MEMORY_ASSET =
  "data/generated-assets/mission-control/space-control-board-transparent.png?v=control-board-memory-20260521";

const CONTROL_BOARD_BUTTONS = [
  {
    id: "red",
    label: "Red",
    cue: "low rocket hum",
    color: "#ff5a48",
    x: 10.63,
    y: 43.16,
    size: 12.4,
    frequency: 196,
    wave: "sine",
  },
  {
    id: "yellow",
    label: "Yellow",
    cue: "bright sunny beep",
    color: "#ffd84f",
    x: 27.26,
    y: 43.34,
    size: 12.4,
    frequency: 262,
    wave: "triangle",
  },
  {
    id: "green",
    label: "Green",
    cue: "soft go chime",
    color: "#67f08d",
    x: 43.63,
    y: 42.75,
    size: 12.4,
    frequency: 330,
    wave: "sine",
  },
  {
    id: "blue",
    label: "Blue",
    cue: "cool wave tone",
    color: "#5bb8ff",
    x: 59.58,
    y: 42.78,
    size: 12.4,
    frequency: 392,
    wave: "sine",
  },
  {
    id: "purple",
    label: "Purple",
    cue: "tiny star twinkle",
    color: "#b880ff",
    x: 76.7,
    y: 42.74,
    size: 12.4,
    frequency: 523,
    wave: "triangle",
  },
];

const CONTROL_BOARD_ROUNDS = [
  ["red", "yellow"],
  ["red", "yellow", "green"],
  ["blue", "green", "yellow"],
  ["red", "purple", "blue", "green"],
  ["yellow", "green", "blue", "purple", "red"],
];

function controlBoardButtonById(id) {
  return CONTROL_BOARD_BUTTONS.find((button) => button.id === id);
}

function ControlBoardMemoryLevel({ onExit }) {
  const [roundIndex, setRoundIndex] = useState(0);
  const [activeButtonId, setActiveButtonId] = useState(null);
  const [pressedButtonId, setPressedButtonId] = useState(null);
  const [inputIndex, setInputIndex] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);
  const [selectedButtonIndex, setSelectedButtonIndex] = useState(0);
  const [message, setMessage] = useState("Listen to the lights.");
  const [mistakes, setMistakes] = useState(0);
  const [won, setWon] = useState(false);
  const timersRef = useRef([]);
  const audioRef = useRef(null);
  const roundRef = useRef(0);
  const inputRef = useRef(0);
  const playingRef = useRef(false);
  const wonRef = useRef(false);
  const celebrationShownRef = useRef(false);
  const sequence = CONTROL_BOARD_ROUNDS[roundIndex] || CONTROL_BOARD_ROUNDS[0];
  const selectedButton = CONTROL_BOARD_BUTTONS[selectedButtonIndex] || CONTROL_BOARD_BUTTONS[0];
  const screenButton = controlBoardButtonById(activeButtonId || pressedButtonId);
  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;
  };

  const ensureAudio = () => {
    const AudioContext = window.AudioContext || window.webkitAudioContext;
    if (!AudioContext) return null;
    if (!audioRef.current) audioRef.current = new AudioContext();
    if (audioRef.current.state === "suspended") {
      audioRef.current.resume().catch(() => {});
    }
    return audioRef.current;
  };

  const playButtonCue = (button, duration = 0.34) => {
    const audio = ensureAudio();
    if (!audio || !button) return;
    const startedAt = audio.currentTime;
    const oscillator = audio.createOscillator();
    const gain = audio.createGain();
    oscillator.type = button.wave || "sine";
    oscillator.frequency.setValueAtTime(button.frequency, startedAt);
    oscillator.frequency.exponentialRampToValueAtTime(
      button.frequency * 1.08,
      startedAt + duration * 0.75,
    );
    gain.gain.setValueAtTime(0.001, startedAt);
    gain.gain.exponentialRampToValueAtTime(0.18, startedAt + 0.035);
    gain.gain.exponentialRampToValueAtTime(0.001, startedAt + duration);
    oscillator.connect(gain);
    gain.connect(audio.destination);
    oscillator.start(startedAt);
    oscillator.stop(startedAt + duration + 0.04);
  };

  const playPattern = (round = roundRef.current) => {
    const nextSequence = CONTROL_BOARD_ROUNDS[round] || CONTROL_BOARD_ROUNDS[0];
    clearTimers();
    setInputIndex(0);
    inputRef.current = 0;
    setPressedButtonId(null);
    setIsPlaying(true);
    playingRef.current = true;
    setMessage("Watch and listen.");
    nextSequence.forEach((buttonId, index) => {
      schedule(() => {
        const button = controlBoardButtonById(buttonId);
        setActiveButtonId(buttonId);
        setSelectedButtonIndex(Math.max(0, CONTROL_BOARD_BUTTONS.findIndex((item) => item.id === buttonId)));
        playButtonCue(button, 0.36);
      }, 480 + index * 760);
      schedule(() => setActiveButtonId(null), 980 + index * 760);
    });
    schedule(() => {
      setActiveButtonId(null);
      setIsPlaying(false);
      playingRef.current = false;
      setMessage("Your turn. Tap the same pattern.");
    }, 620 + nextSequence.length * 760);
  };

  useEffect(() => {
    roundRef.current = roundIndex;
  }, [roundIndex]);

  useEffect(() => {
    wonRef.current = won;
  }, [won]);

  useEffect(() => {
    window.scrollTo({ top: 0, left: 0 });
    playPattern(0);
    return () => {
      clearTimers();
      if (audioRef.current && typeof audioRef.current.close === "function") {
        audioRef.current.close().catch(() => {});
      }
    };
  }, []);

  const finishGame = () => {
    setWon(true);
    wonRef.current = true;
    setMessage("Engine awake. Pattern pilot complete.");
    playKidSound("success");
    if (!celebrationShownRef.current) {
      celebrationShownRef.current = true;
      window.SpaceExplorerFoundation?.celebrateGameFinish?.({
        gameId: "control-board-memory",
        emoji: "*",
        title: "Pattern pilot!",
        message: "You listened, remembered, and tapped the lights.",
      });
    }
  };

  const advanceRound = () => {
    const nextRound = roundRef.current + 1;
    if (nextRound >= CONTROL_BOARD_ROUNDS.length) {
      finishGame();
      return;
    }
    setRoundIndex(nextRound);
    roundRef.current = nextRound;
    setInputIndex(0);
    inputRef.current = 0;
    setMessage("Good listening. Next pattern is coming.");
    playKidSound("chime");
    schedule(() => playPattern(nextRound), 900);
  };

  const pressButton = (button) => {
    if (!button || playingRef.current || wonRef.current) return;
    const target = (CONTROL_BOARD_ROUNDS[roundRef.current] || [])[inputRef.current];
    setSelectedButtonIndex(Math.max(0, CONTROL_BOARD_BUTTONS.findIndex((item) => item.id === button.id)));
    setPressedButtonId(button.id);
    schedule(() => setPressedButtonId(null), 340);
    playButtonCue(button, 0.28);
    if (button.id !== target) {
      setMistakes((count) => count + 1);
      setMessage("Good try. Listen one more time.");
      playKidSound("pop");
      schedule(() => playPattern(roundRef.current), 720);
      return;
    }
    const nextInput = inputRef.current + 1;
    inputRef.current = nextInput;
    setInputIndex(nextInput);
    if (nextInput >= (CONTROL_BOARD_ROUNDS[roundRef.current] || []).length) {
      setMessage("Pattern matched.");
      schedule(advanceRound, 650);
      return;
    }
    setMessage("Yes. Keep going.");
  };

  const replayPattern = () => {
    if (wonRef.current) return;
    setMessage("Listen again.");
    playPattern(roundRef.current);
  };

  const resetGame = () => {
    clearTimers();
    roundRef.current = 0;
    inputRef.current = 0;
    playingRef.current = false;
    wonRef.current = false;
    celebrationShownRef.current = false;
    setRoundIndex(0);
    setInputIndex(0);
    setMistakes(0);
    setWon(false);
    setActiveButtonId(null);
    setPressedButtonId(null);
    setSelectedButtonIndex(0);
    setMessage("Listen to the lights.");
    schedule(() => playPattern(0), 250);
  };

  const moveSelection = (direction) => {
    if (playingRef.current || wonRef.current) return;
    setSelectedButtonIndex((current) => {
      const next =
        (current + direction + CONTROL_BOARD_BUTTONS.length) %
        CONTROL_BOARD_BUTTONS.length;
      const button = CONTROL_BOARD_BUTTONS[next];
      setPressedButtonId(button.id);
      schedule(() => setPressedButtonId(null), 220);
      return next;
    });
    playKidSound("boop");
  };

  useWindowKeyHandler(
    (event) => {
      if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Enter", " "].indexOf(event.key) === -1) {
        return;
      }
      event.preventDefault();
      if (event.key === "ArrowLeft") moveSelection(-1);
      if (event.key === "ArrowRight") moveSelection(1);
      if (event.key === "ArrowDown") replayPattern();
      if (event.key === "ArrowUp" || event.key === "Enter" || event.key === " ") {
        pressButton(CONTROL_BOARD_BUTTONS[selectedButtonIndex]);
      }
    },
    true,
  );

  return (
    <section className="control-board-memory-level" aria-label="Control board memory game">
      <Starfield count={230} />
      <button className="planet-sort-back" onClick={onExit}>
        Back to planets
      </button>
      <div className="control-board-memory-shell">
        <div className="control-board-memory-copy">
          <span>Control Board Memory</span>
          <h1>{won ? "Engine awake!" : "Tap the light pattern"}</h1>
          <p>
            The ship plays colored lights with matching sounds. Repeat the pattern
            to wake the engine.
          </p>
          <div className={`control-board-memory-status ${won ? "done" : ""}`} role="status" aria-live="polite">
            <strong>{message}</strong>
            <small>
              Round {Math.min(roundIndex + 1, CONTROL_BOARD_ROUNDS.length)} of {CONTROL_BOARD_ROUNDS.length}
              {" "}· {inputIndex} of {sequence.length} taps
              {mistakes ? ` · ${mistakes} replays` : ""}
            </small>
          </div>
          <div className="control-board-memory-pattern" aria-label="Pattern progress">
            {sequence.map((buttonId, index) => {
              const button = controlBoardButtonById(buttonId);
              return (
                <span
                  key={`${buttonId}-${index}`}
                  className={index < inputIndex ? "done" : index === inputIndex ? "next" : ""}
                  style={{ "--control-board-button-color": button?.color || "#7ee7ff" }}
                >
                  {index + 1}
                </span>
              );
            })}
          </div>
          <div className="control-board-memory-clues" aria-label="Sound clues">
            {CONTROL_BOARD_BUTTONS.map((button) => (
              <span key={button.id} style={{ "--control-board-button-color": button.color }}>
                <i aria-hidden="true" />
                {button.label}: {button.cue}
              </span>
            ))}
          </div>
          <div className="control-board-memory-actions">
            <button onClick={replayPattern} disabled={isPlaying || won}>
              Hear pattern
            </button>
            <button onClick={resetGame}>Play again</button>
            {won ? <button onClick={onExit}>Done</button> : null}
          </div>
        </div>

        <div className="control-board-memory-play">
          <div className="control-board-memory-board-wrap">
            <SafeAssetImage
              className="control-board-memory-board"
              src={CONTROL_BOARD_MEMORY_ASSET}
              alt="Unlit spaceship control board with large colored buttons"
              context="ControlBoardMemory:board"
              fallbackText="Control board is loading."
            />
            <span className="control-board-memory-radar-sweep" aria-hidden="true" />
            <div
              className={`control-board-memory-screen-letters ${screenButton ? "is-lit" : ""}`}
              aria-hidden="true"
            >
              {screenButton ? (
                <span
                  style={{ "--control-board-button-color": screenButton.color }}
                >
                  {screenButton.label.slice(0, 1)}
                </span>
              ) : null}
            </div>
            {CONTROL_BOARD_BUTTONS.map((button, index) => {
              const isActive = activeButtonId === button.id;
              const isPressed = pressedButtonId === button.id;
              const isSelected = selectedButtonIndex === index && !won;
              return (
                <button
                  key={button.id}
                  className={[
                    "control-board-memory-hotspot",
                    `control-board-memory-hotspot-${button.id}`,
                    isActive ? "is-active" : "",
                    isPressed ? "is-pressed" : "",
                    isSelected ? "is-selected" : "",
                  ]
                    .filter(Boolean)
                    .join(" ")}
                  style={{
                    "--control-board-button-color": button.color,
                    left: `${button.x}%`,
                    top: `${button.y}%`,
                    width: `${button.size}%`,
                    height: `${button.size}%`,
                  }}
                  onClick={() => pressButton(button)}
                  disabled={isPlaying || won}
                  data-control-button={button.id}
                  aria-label={`${button.label} button, ${button.cue}`}
                >
                  <span>{button.label}</span>
                </button>
              );
            })}
          </div>
          <div className="control-board-memory-arrow-pad" aria-label="Arrow helpers">
            <button onClick={() => moveSelection(-1)} disabled={isPlaying || won} aria-label="Move helper left">
              &lt;
            </button>
            <button onClick={() => pressButton(selectedButton)} disabled={isPlaying || won}>
              Tap {selectedButton.label}
            </button>
            <button onClick={() => moveSelection(1)} disabled={isPlaying || won} aria-label="Move helper right">
              &gt;
            </button>
          </div>
        </div>
      </div>
    </section>
  );
}

window.SpaceExplorerControlBoardMemory = {
  buttons: CONTROL_BOARD_BUTTONS,
  rounds: CONTROL_BOARD_ROUNDS,
};
