const spaceReadingFoundation = window.SpaceExplorerFoundation || {};
const SpaceReadingSafeAssetImage =
  spaceReadingFoundation.SafeAssetImage ||
  (({ src, alt = "", className = "" }) => (
    <img className={className} src={src} alt={alt} />
  ));
const spaceReadingUseEscapeHandler =
  spaceReadingFoundation.useEscapeHandler || (() => {});
const spaceReadingUseWindowKeyHandler =
  spaceReadingFoundation.useWindowKeyHandler || (() => {});
const spaceReadingHasNarrationClip =
  spaceReadingFoundation.hasNarrationClip || (() => false);
const spaceReadingPlayNarration =
  spaceReadingFoundation.playNarration || (() => {});
const spaceReadingStopNarration =
  spaceReadingFoundation.stopNarration || (() => {});

const SPACE_READING_PULL_COMPLETE = 0.96;

function spaceReadingWordClip(word) {
  return `space-reading-word-${String(word || "")
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")}.mp3`;
}

const SPACE_READING_CARDS = [
  {
    word: "Sun",
    clue: "The Sun is our warm star.",
    image: "data/generated-assets/space-reading/space-reading-01-sun.png",
    audio: spaceReadingWordClip("Sun"),
  },
  {
    word: "Rocket",
    clue: "A rocket pushes up with hot gas.",
    image: "data/generated-assets/space-reading/space-reading-02-rocket.png",
    audio: spaceReadingWordClip("Rocket"),
  },
  {
    word: "Ship",
    clue: "A space ship can fly above Earth.",
    image: "data/generated-assets/space-reading/space-reading-03-ship.png",
    audio: spaceReadingWordClip("Ship"),
  },
  {
    word: "Booster",
    clue: "Boosters help a rocket lift off.",
    image: "data/generated-assets/space-reading/space-reading-04-booster.png",
    audio: spaceReadingWordClip("Booster"),
  },
  {
    word: "Helmet",
    clue: "A helmet helps keep air in.",
    image: "data/generated-assets/space-reading/space-reading-05-helmet.png",
    audio: spaceReadingWordClip("Helmet"),
  },
  {
    word: "Suit",
    clue: "A space suit keeps a body safe.",
    image: "data/generated-assets/space-reading/space-reading-06-suit.png",
    audio: spaceReadingWordClip("Suit"),
  },
  {
    word: "Rover",
    clue: "A rover rolls on far ground.",
    image: "data/generated-assets/space-reading/space-reading-07-rover.png",
    audio: spaceReadingWordClip("Rover"),
  },
  {
    word: "Probe",
    clue: "A probe visits space without people.",
    image: "data/generated-assets/space-reading/space-reading-08-probe.png",
    audio: spaceReadingWordClip("Probe"),
  },
  {
    word: "Station",
    clue: "A station is a home in orbit.",
    image: "data/generated-assets/space-reading/space-reading-09-station.png",
    audio: spaceReadingWordClip("Station"),
  },
  {
    word: "Dish",
    clue: "A dish listens and talks to space.",
    image: "data/generated-assets/space-reading/space-reading-10-dish.png",
    audio: spaceReadingWordClip("Dish"),
  },
  {
    word: "Panel",
    clue: "A panel catches light for power.",
    image: "data/generated-assets/space-reading/space-reading-11-panel.png",
    audio: spaceReadingWordClip("Panel"),
  },
  {
    word: "Orbit",
    clue: "Orbit means going around.",
    image: "data/generated-assets/space-reading/space-reading-12-orbit.png",
    audio: spaceReadingWordClip("Orbit"),
  },
  {
    word: "Moon",
    clue: "The Moon goes around Earth.",
    image: "data/generated-assets/space-reading/space-reading-13-moon.png",
    audio: spaceReadingWordClip("Moon"),
  },
  {
    word: "Crater",
    clue: "A crater is a round dent.",
    image: "data/generated-assets/space-reading/space-reading-14-crater.png",
    audio: spaceReadingWordClip("Crater"),
  },
  {
    word: "Comet",
    clue: "A comet is ice and dust.",
    image: "data/generated-assets/space-reading/space-reading-15-comet.png",
    audio: spaceReadingWordClip("Comet"),
  },
  {
    word: "Rock",
    clue: "Space rocks can be very old.",
    image: "data/generated-assets/space-reading/space-reading-16-rock.png",
    audio: spaceReadingWordClip("Rock"),
  },
  {
    word: "Star",
    clue: "A star is a far hot sun.",
    image: "data/generated-assets/space-reading/space-reading-17-star.png",
    audio: spaceReadingWordClip("Star"),
  },
  {
    word: "Earth",
    clue: "Earth is our blue home.",
    image: "data/generated-assets/space-reading/space-reading-18-earth.png",
    audio: spaceReadingWordClip("Earth"),
  },
  {
    word: "Mars",
    clue: "Mars has red dusty ground.",
    image: "data/generated-assets/space-reading/space-reading-19-mars.png",
    audio: spaceReadingWordClip("Mars"),
  },
  {
    word: "Ring",
    clue: "A ring can be ice and rock.",
    image: "data/generated-assets/space-reading/space-reading-20-ring.png",
    audio: spaceReadingWordClip("Ring"),
  },
  {
    word: "Cloud",
    clue: "Some worlds have thick clouds.",
    image: "data/generated-assets/space-reading/space-reading-21-cloud.png",
    audio: spaceReadingWordClip("Cloud"),
  },
  {
    word: "Storm",
    clue: "A big storm can spin for years.",
    image: "data/generated-assets/space-reading/space-reading-22-storm.png",
    audio: spaceReadingWordClip("Storm"),
  },
  {
    word: "Black Hole",
    clue: "A black hole pulls light close.",
    image: "data/generated-assets/space-reading/space-reading-23-black-hole.png",
    audio: spaceReadingWordClip("Black Hole"),
  },
  {
    word: "Galaxy",
    clue: "A galaxy is a huge star family.",
    image: "data/generated-assets/space-reading/space-reading-24-galaxy.png",
    audio: spaceReadingWordClip("Galaxy"),
  },
  {
    word: "Nebula",
    clue: "A nebula is a cloud in space.",
    image: "data/generated-assets/space-reading/space-reading-25-nebula.png",
    audio: spaceReadingWordClip("Nebula"),
  },
  {
    word: "Asteroid",
    clue: "An asteroid is a rocky world piece.",
    image: "data/generated-assets/space-reading/space-reading-26-asteroid.png",
    audio: spaceReadingWordClip("Asteroid"),
  },
  {
    word: "Telescope",
    clue: "A telescope helps eyes see far.",
    image: "data/generated-assets/space-reading/space-reading-27-telescope.png",
    audio: spaceReadingWordClip("Telescope"),
  },
  {
    word: "Satellite",
    clue: "A satellite travels around a world.",
    image: "data/generated-assets/space-reading/space-reading-28-satellite.png",
    audio: spaceReadingWordClip("Satellite"),
  },
  {
    word: "Capsule",
    clue: "A capsule carries astronauts safely.",
    image: "data/generated-assets/space-reading/space-reading-29-capsule.png",
    audio: spaceReadingWordClip("Capsule"),
  },
  {
    word: "Launch",
    clue: "Launch means blast off from the ground.",
    image: "data/generated-assets/space-reading/space-reading-30-launch.png",
    audio: spaceReadingWordClip("Launch"),
  },
  {
    word: "Astronaut",
    clue: "An astronaut is a space explorer.",
    image: "data/generated-assets/space-reading/space-reading-31-astronaut.png",
    audio: spaceReadingWordClip("Astronaut"),
  },
  {
    word: "Gravity",
    clue: "Gravity pulls things together.",
    image: "data/generated-assets/space-reading/space-reading-32-gravity.png",
    audio: spaceReadingWordClip("Gravity"),
  },
  {
    word: "Eclipse",
    clue: "An eclipse makes a shadow in space.",
    image: "data/generated-assets/space-reading/space-reading-33-eclipse.png",
    audio: spaceReadingWordClip("Eclipse"),
  },
  {
    word: "Meteor",
    clue: "A meteor streaks through the sky.",
    image: "data/generated-assets/space-reading/space-reading-34-meteor.png",
    audio: spaceReadingWordClip("Meteor"),
  },
  {
    word: "Milky Way",
    clue: "The Milky Way is our galaxy home.",
    image: "data/generated-assets/space-reading/space-reading-35-milky-way.png",
    audio: spaceReadingWordClip("Milky Way"),
  },
  {
    word: "Solar Flare",
    clue: "A solar flare is a bright Sun burst.",
    image: "data/generated-assets/space-reading/space-reading-36-solar-flare.png",
    audio: spaceReadingWordClip("Solar Flare"),
  },
  {
    word: "Spacewalk",
    clue: "A spacewalk happens outside the ship.",
    image: "data/generated-assets/space-reading/space-reading-37-spacewalk.png",
    audio: spaceReadingWordClip("Spacewalk"),
  },
  {
    word: "Docking",
    clue: "Docking means ships connect in space.",
    image: "data/generated-assets/space-reading/space-reading-38-docking.png",
    audio: spaceReadingWordClip("Docking"),
  },
  {
    word: "Landing",
    clue: "Landing means coming safely down.",
    image: "data/generated-assets/space-reading/space-reading-39-landing.png",
    audio: spaceReadingWordClip("Landing"),
  },
  {
    word: "Footprint",
    clue: "A footprint shows where a boot stepped.",
    image: "data/generated-assets/space-reading/space-reading-40-footprint.png",
    audio: spaceReadingWordClip("Footprint"),
  },
  {
    word: "Moon Dust",
    clue: "Moon dust is soft gray powder.",
    image: "data/generated-assets/space-reading/space-reading-41-moon-dust.png",
    audio: spaceReadingWordClip("Moon Dust"),
  },
  {
    word: "Control Room",
    clue: "A control room helps guide missions.",
    image: "data/generated-assets/space-reading/space-reading-42-control-room.png",
    audio: spaceReadingWordClip("Control Room"),
  },
  {
    word: "Antenna",
    clue: "An antenna sends and catches signals.",
    image: "data/generated-assets/space-reading/space-reading-43-antenna.png",
    audio: spaceReadingWordClip("Antenna"),
  },
  {
    word: "Solar Sail",
    clue: "A solar sail rides light from the Sun.",
    image: "data/generated-assets/space-reading/space-reading-44-solar-sail.png",
    audio: spaceReadingWordClip("Solar Sail"),
  },
  {
    word: "Explorer",
    clue: "An explorer looks for new things.",
    image: "data/generated-assets/space-reading/space-reading-45-explorer.png",
    audio: spaceReadingWordClip("Explorer"),
  },
  {
    word: "Voyager",
    clue: "Voyager is a brave space probe.",
    image: "data/generated-assets/space-reading/space-reading-46-voyager.png",
    audio: spaceReadingWordClip("Voyager"),
  },
  {
    word: "Dwarf Planet",
    clue: "A dwarf planet is a small round world.",
    image: "data/generated-assets/space-reading/space-reading-47-dwarf-planet.png",
    audio: spaceReadingWordClip("Dwarf Planet"),
  },
  {
    word: "Ice Moon",
    clue: "An ice moon has frozen water.",
    image: "data/generated-assets/space-reading/space-reading-48-ice-moon.png",
    audio: spaceReadingWordClip("Ice Moon"),
  },
  {
    word: "Lunar Base",
    clue: "A lunar base is a Moon home.",
    image: "data/generated-assets/space-reading/space-reading-49-lunar-base.png",
    audio: spaceReadingWordClip("Lunar Base"),
  },
  {
    word: "Mars Base",
    clue: "A Mars base is a red planet home.",
    image: "data/generated-assets/space-reading/space-reading-50-mars-base.png",
    audio: spaceReadingWordClip("Mars Base"),
  },
  {
    word: "Airlock",
    clue: "An airlock keeps air inside the ship.",
    image: "data/generated-assets/space-reading/space-reading-51-airlock.png",
    audio: spaceReadingWordClip("Airlock"),
  },
  {
    word: "Command",
    clue: "Command means giving the mission a plan.",
    image: "data/generated-assets/space-reading/space-reading-52-command.png",
    audio: spaceReadingWordClip("Command"),
  },
  {
    word: "Countdown",
    clue: "A countdown gets rockets ready.",
    image: "data/generated-assets/space-reading/space-reading-53-countdown.png",
    audio: spaceReadingWordClip("Countdown"),
  },
  {
    word: "Mission",
    clue: "A mission is a special space job.",
    image: "data/generated-assets/space-reading/space-reading-54-mission.png",
    audio: spaceReadingWordClip("Mission"),
  },
  {
    word: "Orbit Path",
    clue: "An orbit path goes around a world.",
    image: "data/generated-assets/space-reading/space-reading-55-orbit-path.png",
    audio: spaceReadingWordClip("Orbit Path"),
  },
  {
    word: "Rocket Flame",
    clue: "Rocket flame pushes the ship up.",
    image: "data/generated-assets/space-reading/space-reading-56-rocket-flame.png",
    audio: spaceReadingWordClip("Rocket Flame"),
  },
  {
    word: "Space Boots",
    clue: "Space boots grip dusty ground.",
    image: "data/generated-assets/space-reading/space-reading-57-space-boots.png",
    audio: spaceReadingWordClip("Space Boots"),
  },
  {
    word: "Moon Buggy",
    clue: "A Moon buggy rolls on the Moon.",
    image: "data/generated-assets/space-reading/space-reading-58-moon-buggy.png",
    audio: spaceReadingWordClip("Moon Buggy"),
  },
  {
    word: "Star Map",
    clue: "A star map helps explorers point the way.",
    image: "data/generated-assets/space-reading/space-reading-59-star-map.png",
    audio: spaceReadingWordClip("Star Map"),
  },
  {
    word: "Space Food",
    clue: "Space food is packed for zero gravity.",
    image: "data/generated-assets/space-reading/space-reading-60-space-food.png",
    audio: spaceReadingWordClip("Space Food"),
  },
  {
    word: "Water Ice",
    clue: "Water ice can hide on cold worlds.",
    image: "data/generated-assets/space-reading/space-reading-61-water-ice.png",
    audio: spaceReadingWordClip("Water Ice"),
  },
  {
    word: "Red Spot",
    clue: "The Red Spot is Jupiter's huge storm.",
    image: "data/generated-assets/space-reading/space-reading-62-red-spot.png",
    audio: spaceReadingWordClip("Red Spot"),
  },
  {
    word: "Gas Giant",
    clue: "A gas giant is a giant cloudy planet.",
    image: "data/generated-assets/space-reading/space-reading-63-gas-giant.png",
    audio: spaceReadingWordClip("Gas Giant"),
  },
  {
    word: "Ice Giant",
    clue: "An ice giant is a cold far planet.",
    image: "data/generated-assets/space-reading/space-reading-64-ice-giant.png",
    audio: spaceReadingWordClip("Ice Giant"),
  },
  {
    word: "Ring Gap",
    clue: "A ring gap is space between rings.",
    image: "data/generated-assets/space-reading/space-reading-65-ring-gap.png",
    audio: spaceReadingWordClip("Ring Gap"),
  },
  {
    word: "Moonrise",
    clue: "Moonrise is the Moon coming up.",
    image: "data/generated-assets/space-reading/space-reading-66-moonrise.png",
    audio: spaceReadingWordClip("Moonrise"),
  },
  {
    word: "Sunrise",
    clue: "Sunrise starts a bright new day.",
    image: "data/generated-assets/space-reading/space-reading-67-sunrise.png",
    audio: spaceReadingWordClip("Sunrise"),
  },
  {
    word: "Shadow",
    clue: "A shadow shows where light is blocked.",
    image: "data/generated-assets/space-reading/space-reading-68-shadow.png",
    audio: spaceReadingWordClip("Shadow"),
  },
  {
    word: "Magnet",
    clue: "A magnet can pull some metals.",
    image: "data/generated-assets/space-reading/space-reading-69-magnet.png",
    audio: spaceReadingWordClip("Magnet"),
  },
  {
    word: "Signal",
    clue: "A signal carries a message through space.",
    image: "data/generated-assets/space-reading/space-reading-70-signal.png",
    audio: spaceReadingWordClip("Signal"),
  },
  {
    word: "Radar",
    clue: "Radar bounces waves to find things.",
    image: "data/generated-assets/space-reading/space-reading-71-radar.png",
    audio: spaceReadingWordClip("Radar"),
  },
  {
    word: "Parachute",
    clue: "A parachute slows a capsule down.",
    image: "data/generated-assets/space-reading/space-reading-72-parachute.png",
    audio: spaceReadingWordClip("Parachute"),
  },
  {
    word: "Heat Shield",
    clue: "A heat shield guards a hot return.",
    image: "data/generated-assets/space-reading/space-reading-73-heat-shield.png",
    audio: spaceReadingWordClip("Heat Shield"),
  },
  {
    word: "Space Garden",
    clue: "A space garden grows plants away from Earth.",
    image: "data/generated-assets/space-reading/space-reading-74-space-garden.png",
    audio: spaceReadingWordClip("Space Garden"),
  },
  {
    word: "Home Planet",
    clue: "Earth is our home planet.",
    image: "data/generated-assets/space-reading/space-reading-75-home-planet.png",
    audio: spaceReadingWordClip("Home Planet"),
  },
];

function SpaceReadingDeck({ onExit }) {
  const [index, setIndex] = useState(0);
  const [pullProgress, setPullProgress] = useState(0);
  const [didReadCard, setDidReadCard] = useState(false);
  const card = SPACE_READING_CARDS[index] || SPACE_READING_CARDS[0];
  const lastIndex = SPACE_READING_CARDS.length - 1;
  const highlightPercent = Math.round(pullProgress * 100);
  const sliderValue = Math.round(pullProgress * 100);
  const canReadCard = spaceReadingHasNarrationClip(card.audio);

  const goToCard = (nextIndex) => {
    const safeIndex = Math.max(0, Math.min(lastIndex, nextIndex));
    setIndex(safeIndex);
    setPullProgress(0);
    setDidReadCard(false);
    spaceReadingStopNarration();
    if (typeof playKidSound === "function") playKidSound("boop");
  };

  const go = (step) => {
    const nextIndex = (index + step + SPACE_READING_CARDS.length) %
      SPACE_READING_CARDS.length;
    goToCard(nextIndex);
  };

  useEffect(() => {
    [SPACE_READING_CARDS[index + 1], SPACE_READING_CARDS[index - 1]].forEach(
      (item) => {
        if (!item || !item.image) return;
        const image = new Image();
        image.decoding = "async";
        image.src = item.image;
      },
    );
  }, [index]);

  useEffect(() => {
    setPullProgress(0);
    setDidReadCard(false);
    spaceReadingStopNarration();
    const unsubscribe = window.__narration?.onEnded?.((clip) => {
      if (clip !== card.audio) return;
      setDidReadCard(false);
      setPullProgress(0);
    });
    return () => {
      if (typeof unsubscribe === "function") unsubscribe();
    };
  }, [card.audio]);

  useEffect(() => () => spaceReadingStopNarration(), []);

  const triggerWordRead = () => {
    setPullProgress(1);
    setDidReadCard(true);
    if (canReadCard) {
      spaceReadingPlayNarration(card.audio);
    } else if (typeof playKidSound === "function") {
      playKidSound("chime");
      window.setTimeout(() => {
        setDidReadCard(false);
        setPullProgress(0);
      }, 650);
    }
  };

  const handlePullChange = (event) => {
    const nextProgress = Math.max(
      0,
      Math.min(1, Number(event.target.value || 0) / 100),
    );
    if (didReadCard) {
      setPullProgress(1);
      return;
    }
    setPullProgress(nextProgress);
    if (nextProgress >= SPACE_READING_PULL_COMPLETE) {
      triggerWordRead();
    }
  };

  const handlePullRelease = () => {
    if (!didReadCard) setPullProgress(0);
  };

  spaceReadingUseEscapeHandler(onExit, true);
  spaceReadingUseWindowKeyHandler((event) => {
    if (event.key === "ArrowRight" || event.key === " " || event.key === "Enter") {
      event.preventDefault();
      go(1);
    } else if (event.key === "ArrowLeft") {
      event.preventDefault();
      go(-1);
    }
  });

  return (
    <main className="space-reading-page" aria-label="Space reading words">
      <button className="space-reading-menu" type="button" onClick={onExit}>
        ☰
      </button>
      <button
        className="space-reading-arrow left"
        type="button"
        onClick={() => go(-1)}
        aria-label="Previous word"
      >
        ‹
      </button>
      <button
        className="space-reading-arrow right"
        type="button"
        onClick={() => go(1)}
        aria-label="Next word"
      >
        ›
      </button>
      <SpaceReadingSafeAssetImage
        key={card.image}
        className="space-reading-image"
        src={card.image}
        alt=""
        decoding="async"
        context={`SpaceReading:${card.word}`}
        fallbackClassName="space-reading-image-fallback"
        fallbackText="Space picture is loading."
      />
      <section className="space-reading-word-panel" aria-live="polite">
        <p>{card.clue}</p>
        <h1
          className={`space-reading-word ${pullProgress > 0 ? "is-active" : ""}`}
          style={{ "--space-reading-fill": `${highlightPercent}%` }}
        >
          <span>{card.word}</span>
        </h1>
        <div className="space-reading-slider-shell">
          <label className="space-reading-slider-label" htmlFor="space-reading-slider">
            Pull to read
          </label>
          <input
            id="space-reading-slider"
            className="space-reading-slider"
            type="range"
            min="0"
            max="100"
            step="1"
            value={sliderValue}
            onInput={handlePullChange}
            onChange={handlePullChange}
            onMouseUp={handlePullRelease}
            onTouchEnd={handlePullRelease}
            onPointerUp={handlePullRelease}
            aria-label={`Pull to hear ${card.word}`}
            style={{ "--space-reading-fill": `${sliderValue}%` }}
          />
        </div>
        <div className="space-reading-count">
          {index + 1} / {SPACE_READING_CARDS.length}
        </div>
      </section>
    </main>
  );
}

window.SpaceExplorerReading = {
  SPACE_READING_CARDS,
  SpaceReadingDeck,
};
