(() => {
  const nightFinder = document.querySelector("[data-night-finder]");
  if (!(nightFinder instanceof HTMLElement)) return;

  const state = {
    team: "pair",
    mood: "cinematic",
    travel: "nearby",
    pace: "classic"
  };
  const roomsDataNode = nightFinder.querySelector("[data-finder-rooms]");
  const rooms = roomsDataNode?.textContent ? JSON.parse(roomsDataNode.textContent) : [];
  const resultBody = nightFinder.querySelector("[data-finder-result-body]");
  const resultLink = nightFinder.querySelector("[data-finder-result-link]");
  const resultList = nightFinder.querySelector("[data-finder-results]");
  const collectionRoutes = {
    cinematic: "/collections/our-favourite-rooms/",
    puzzle: "/collections/puzzle-heavy-escape-rooms-worth-travelling-for/",
    scary: "/collections/scary-escape-rooms-worth-travelling-for/",
    adventure: "/collections/adventure-escape-rooms/"
  };
  const moodWords = {
    cinematic: ["story", "cinematic", "immersive", "theatre", "actor", "production", "set", "atmosphere", "occasion", "heist", "bank", "film", "show"],
    puzzle: ["puzzle", "logic", "clever", "flow", "deduction", "challenge", "riddle", "mechanical", "code", "cipher", "lab", "mystery"],
    scary: ["scary", "horror", "haunt", "tense", "terror", "dark", "fear", "ghost", "nightmare", "cabin", "asylum", "curse", "zombie", "witch", "vampire", "coffin", "slaughter"],
    adventure: ["adventure", "quest", "pirate", "temple", "jungle", "expedition", "treasure", "explorer", "diary", "island", "magic", "dragon"]
  };
  const teamTargets = {
    pair: { size: 2, label: "pairs" },
    group: { size: 4, label: "groups of 3-5" },
    crew: { size: 6, label: "bigger teams" }
  };

  function escapeHtml(value) {
    return String(value ?? "").replace(/[&<>"']/g, (character) => ({
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      "\"": "&quot;",
      "'": "&#39;"
    }[character]));
  }

  function roomScore(room) {
    const target = teamTargets[state.team] || teamTargets.pair;
    let score = 0;
    const minPlayers = Number.isFinite(room.minPlayers) ? room.minPlayers : 1;
    const maxPlayers = Number.isFinite(room.maxPlayers) ? room.maxPlayers : 99;
    if (minPlayers <= target.size && maxPlayers >= target.size) score += 34;
    if (state.team === "pair" && minPlayers <= 2) score += 12;
    if (state.team === "crew" && maxPlayers >= 6) score += 12;

    const text = String(room.searchText || "").toLocaleLowerCase("en-GB");
    const words = moodWords[state.mood] || moodWords.cinematic;
    const moodMatches = words.reduce((total, word) => total + (text.includes(word) ? 1 : 0), 0);
    score += moodMatches > 0 ? Math.min(42, moodMatches * 16) : -20;

    const duration = Number.isFinite(room.durationMinutes) ? room.durationMinutes : 60;
    if (state.pace === "classic") score += duration <= 65 ? 16 : 4;
    if (state.pace === "extended") score += duration > 65 ? 18 : 2;
    if (state.travel === "destination") score += text.includes("terpeca") || text.includes("award") || text.includes("favourite") ? 18 : 7;
    if (state.travel === "nearby") score += 8;
    return score;
  }

  function matchReason(room) {
    const target = teamTargets[state.team] || teamTargets.pair;
    const moodLabel = {
      cinematic: "story-led",
      puzzle: "puzzle-first",
      scary: "tense",
      adventure: "adventure-led"
    }[state.mood] || "story-led";
    const duration = Number.isFinite(room.durationMinutes) ? `${room.durationMinutes} min` : "runtime listed";
    const travel = state.travel === "destination" ? "worth comparing for a trip" : `start near ${room.locationName || "your plan"}`;
    return `${moodLabel} fit for ${target.label}; ${duration}; ${travel}.`;
  }

  function roomMeta(room) {
    const items = [];
    if (Number.isFinite(room.minPlayers) && Number.isFinite(room.maxPlayers)) items.push(`${room.minPlayers}-${room.maxPlayers} players`);
    if (Number.isFinite(room.durationMinutes)) items.push(`${room.durationMinutes} min`);
    if (room.difficultyLabel) items.push(room.difficultyLabel);
    return items.slice(0, 3);
  }

  function syncNightFinder() {
    const matches = [...rooms]
      .map((room) => ({ ...room, score: roomScore(room) }))
      .sort((left, right) => right.score - left.score || left.roomName.localeCompare(right.roomName))
      .slice(0, 4);
    const target = teamTargets[state.team] || teamTargets.pair;
    const routeHref = state.travel === "destination" ? collectionRoutes[state.mood] || "/collections/" : "/rooms/#collection-controls";
    if (resultBody) resultBody.textContent = `${matches.length} starting points for ${target.label}; change any choice and this list updates.`;
    if (resultLink instanceof HTMLAnchorElement) resultLink.href = routeHref;
    if (resultList) {
      resultList.innerHTML = matches.map((room, index) => `
        <a class="night-finder-room" href="${escapeHtml(room.href)}">
          <span class="night-finder-rank">${String(index + 1).padStart(2, "0")}</span>
          <span class="night-finder-thumb"><img src="${escapeHtml(room.image)}" alt="${escapeHtml(room.imageAlt)}" data-room-fallback-src="${escapeHtml(room.fallbackImage)}"></span>
          <span class="night-finder-room-copy">
            <strong>${escapeHtml(room.roomName)}</strong>
            <span>${escapeHtml(room.operatorName)} · ${escapeHtml(room.locationName)}</span>
            <span class="night-finder-room-meta">${roomMeta(room).map((item) => `<mark>${escapeHtml(item)}</mark>`).join("")}</span>
            <em>${escapeHtml(matchReason(room))}</em>
          </span>
        </a>
      `).join("");
    }

    for (const option of nightFinder.querySelectorAll("[data-finder-axis]")) {
      if (!(option instanceof HTMLButtonElement)) continue;
      const axis = option.dataset.finderAxis;
      option.setAttribute("aria-pressed", axis ? String(state[axis] === option.dataset.finderValue) : "false");
    }
  }

  for (const option of nightFinder.querySelectorAll("[data-finder-axis]")) {
    if (!(option instanceof HTMLButtonElement)) continue;
    option.addEventListener("click", () => {
      const axis = option.dataset.finderAxis;
      const value = option.dataset.finderValue;
      if (!axis || !value) return;
      state[axis] = value;
      syncNightFinder();
    });
  }

  syncNightFinder();
})();
