(function () {
  const protocol = "localchat.5second.v1";
  const eventSessionCreated = "session.created";
  const eventPlayerJoined = "player.joined";
  const eventRoundStarted = "round.started";
  const eventRoundJudged = "round.judged";
  const eventScoreReset = "score.reset";
  const storageKey = "5-second-challenge-last";
  const roundSeconds = 5;
  const prompts = [
    "Name 3 campus snacks",
    "Name 3 things in a backpack",
    "Name 3 streaming shows",
    "Name 3 sports teams",
    "Name 3 pizza toppings",
    "Name 3 road trip songs",
    "Name 3 phone apps",
    "Name 3 coffee orders",
    "Name 3 weekend plans",
    "Name 3 things at a dorm desk",
    "Name 3 movie villains",
    "Name 3 ice cream flavors",
    "Name 3 study spots",
    "Name 3 group chat names",
    "Name 3 breakfast foods",
    "Name 3 things at a game night",
    "Name 3 excuses for being late",
    "Name 3 karaoke songs"
  ];

  const state = {
    mode: "",
    role: "",
    roomId: "",
    memberId: "",
    memberName: "",
    activePlayer: "Player 1",
    cursor: "0",
    round: null,
    roundIndex: 0,
    scores: {},
    players: {},
    history: [],
    status: "Choose a mode to start.",
    now: Date.now(),
    tickTimer: 0,
    pollTimer: 0
  };

  function api() {
    return window.localchat || {};
  }

  function el(tag, className, text) {
    const node = document.createElement(tag);
    if (className) {
      node.className = className;
    }
    if (text !== undefined && text !== null) {
      node.textContent = text;
    }
    return node;
  }

  function bridge(method, params) {
    const parts = method.split(".");
    let target = api();
    for (let i = 0; i < parts.length; i += 1) {
      target = target && target[parts[i]];
    }
    if (typeof target !== "function") {
      return Promise.resolve({});
    }
    return target(params || {}).catch(function (error) {
      state.status = (error && error.errorMessage) || "Action failed";
      render();
      return {};
    });
  }

  function toast(message) {
    return bridge("ui.showToast", { message: message });
  }

  function storageGet(key) {
    const store = api().storage && api().storage.local;
    if (!store || !store.get) {
      return Promise.resolve("");
    }
    return store.get(key).catch(function () {
      return "";
    });
  }

  function storageSet(key, value) {
    const store = api().storage && api().storage.local;
    if (!store || !store.set) {
      return Promise.resolve();
    }
    return store.set(key, value).catch(function () {});
  }

  function keepScreenOn(enabled) {
    return bridge("ui.setKeepScreenOn", Boolean(enabled));
  }

  function safeId(value, fallback) {
    const raw = String(value || "").trim().replace(/[^a-zA-Z0-9._:-]/g, "-");
    return raw ? raw.slice(0, 80) : fallback;
  }

  function roomCode() {
    return "FIVE-" + Math.floor(1000 + Math.random() * 9000);
  }

  function memberId() {
    return "member-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 7);
  }

  function playerNameFallback() {
    return state.role === "host" ? "Host" : "Player";
  }

  function promptFor(index) {
    return prompts[index % prompts.length];
  }

  function nextPrompt() {
    const prompt = promptFor(state.roundIndex);
    state.roundIndex = (state.roundIndex + 1) % prompts.length;
    return prompt;
  }

  function addPlayer(id, name) {
    const playerId = safeId(id, "");
    if (!playerId) {
      return;
    }
    const playerName = String(name || playerNameFallback()).trim().slice(0, 32) || playerNameFallback();
    state.players[playerId] = { id: playerId, name: playerName };
    if (state.scores[playerName] === undefined) {
      state.scores[playerName] = 0;
    }
  }

  function playerNames() {
    const names = Object.keys(state.players).map(function (id) {
      return state.players[id].name;
    });
    const unique = {};
    names.concat([state.activePlayer, state.memberName]).forEach(function (name) {
      const clean = String(name || "").trim();
      if (clean) {
        unique[clean] = true;
      }
    });
    return Object.keys(unique).sort();
  }

  function scoreRows() {
    const names = Object.keys(state.scores).sort(function (a, b) {
      return state.scores[b] - state.scores[a] || a.localeCompare(b);
    });
    if (!names.length) {
      return [{ name: "No scores yet", score: 0 }];
    }
    return names.map(function (name) {
      return { name: name, score: state.scores[name] || 0 };
    });
  }

  function sendEvent(event, extra) {
    if (!state.roomId) {
      return Promise.resolve({});
    }
    const payload = Object.assign({
      protocol: protocol,
      event: event,
      sessionId: state.roomId,
      memberId: state.memberId,
      memberName: state.memberName,
      createdAt: new Date().toISOString()
    }, extra || {});
    return bridge("room.message", {
      roomId: state.roomId,
      memberId: state.memberId,
      type: "5second.event",
      payload: payload
    });
  }

  function isGamePayload(payload) {
    return payload && payload.protocol === protocol && typeof payload.event === "string";
  }

  function applyPayload(payload) {
    if (!isGamePayload(payload)) {
      return;
    }
    if (payload.event === eventSessionCreated) {
      state.status = "Room " + (payload.sessionId || state.roomId) + " is ready.";
      return;
    }
    if (payload.event === eventPlayerJoined) {
      addPlayer(payload.memberId, payload.memberName);
      if (state.role === "host") {
        state.status = (payload.memberName || "A player") + " joined.";
      }
      return;
    }
    if (payload.event === eventRoundStarted) {
      state.round = {
        id: payload.roundId,
        prompt: payload.prompt || "Name 3 things",
        playerName: payload.playerName || "Player",
        startedAt: payload.startedAt || Date.now(),
        endsAt: payload.endsAt || (Date.now() + roundSeconds * 1000),
        result: ""
      };
      state.activePlayer = state.round.playerName;
      state.status = state.round.playerName + " has 5 seconds.";
      keepScreenOn(true);
      return;
    }
    if (payload.event === eventRoundJudged) {
      judgeRound(payload.success, payload.playerName, payload.prompt, false);
      return;
    }
    if (payload.event === eventScoreReset) {
      state.scores = {};
      state.history = [];
      state.status = "Scoreboard reset.";
    }
  }

  function pollRoom() {
    if (!state.roomId || !api().room || !api().room.poll) {
      return;
    }
    bridge("room.poll", {
      roomId: state.roomId,
      cursor: state.cursor,
      limit: 40
    }).then(function (result) {
      const messages = Array.isArray(result.messages) ? result.messages : [];
      messages.forEach(function (message) {
        if (message && message.memberId !== state.memberId) {
          applyPayload(message.payload);
        }
      });
      if (result.nextCursor !== undefined && result.nextCursor !== null) {
        state.cursor = String(result.nextCursor);
      }
      render();
    });
  }

  function startPolling() {
    stopPolling();
    state.pollTimer = window.setInterval(pollRoom, 1200);
    pollRoom();
  }

  function stopPolling() {
    if (state.pollTimer) {
      window.clearInterval(state.pollTimer);
      state.pollTimer = 0;
    }
  }

  function startTicker() {
    stopTicker();
    state.tickTimer = window.setInterval(function () {
      state.now = Date.now();
      if (state.round && timeLeft() <= 0) {
        keepScreenOn(false);
      }
      render();
    }, 250);
  }

  function stopTicker() {
    if (state.tickTimer) {
      window.clearInterval(state.tickTimer);
      state.tickTimer = 0;
    }
  }

  function timeLeft() {
    if (!state.round || state.round.result) {
      return 0;
    }
    return Math.max(0, Math.ceil((state.round.endsAt - state.now) / 1000));
  }

  function beginRound() {
    const prompt = nextPrompt();
    const playerName = state.activePlayer || state.memberName || "Player";
    const startedAt = Date.now();
    const round = {
      id: "round-" + startedAt.toString(36),
      prompt: prompt,
      playerName: playerName,
      startedAt: startedAt,
      endsAt: startedAt + roundSeconds * 1000,
      result: ""
    };
    state.round = round;
    state.status = playerName + " has 5 seconds.";
    keepScreenOn(true);
    sendEvent(eventRoundStarted, {
      roundId: round.id,
      prompt: round.prompt,
      playerName: round.playerName,
      startedAt: round.startedAt,
      endsAt: round.endsAt
    });
    render();
  }

  function judgeRound(success, playerName, prompt, broadcast) {
    const name = String(playerName || (state.round && state.round.playerName) || "Player").trim() || "Player";
    const text = String(prompt || (state.round && state.round.prompt) || "Name 3 things");
    state.scores[name] = (state.scores[name] || 0) + (success ? 1 : 0);
    state.history.unshift({
      playerName: name,
      prompt: text,
      success: Boolean(success),
      at: new Date().toLocaleTimeString()
    });
    state.history = state.history.slice(0, 6);
    if (state.round) {
      state.round.result = success ? "made" : "missed";
    }
    state.status = name + (success ? " scored." : " missed.");
    keepScreenOn(false);
    if (broadcast !== false) {
      sendEvent(eventRoundJudged, {
        roundId: state.round && state.round.id,
        playerName: name,
        prompt: text,
        success: Boolean(success)
      });
    }
    render();
  }

  function resetScores() {
    state.scores = {};
    state.history = [];
    state.round = null;
    state.status = "Scoreboard reset.";
    sendEvent(eventScoreReset, {});
    render();
  }

  function startSolo() {
    state.mode = "play";
    state.role = "solo";
    state.memberId = memberId();
    state.memberName = "Player 1";
    state.activePlayer = "Player 1";
    state.roomId = "";
    state.status = "Quick play ready.";
    state.scores = { "Player 1": 0 };
    stopPolling();
    startTicker();
    render();
  }

  function startHost(name) {
    state.mode = "play";
    state.role = "host";
    state.memberId = memberId();
    state.memberName = String(name || "Host").trim().slice(0, 32) || "Host";
    state.activePlayer = state.memberName;
    state.roomId = roomCode();
    state.status = "Creating room...";
    state.scores = {};
    addPlayer(state.memberId, state.memberName);
    bridge("room.create", {
      roomId: state.roomId,
      memberId: state.memberId
    }).then(function (result) {
      if (result && result.roomId) {
        state.roomId = result.roomId;
      }
      state.status = "Share room " + state.roomId + " with nearby players.";
      storageSet(storageKey, JSON.stringify({ roomId: state.roomId, name: state.memberName }));
      sendEvent(eventSessionCreated, {});
      startPolling();
      startTicker();
      render();
    });
    render();
  }

  function joinRoom(roomId, name) {
    const cleanRoom = safeId(roomId, "");
    if (!cleanRoom) {
      toast("Enter a room code first");
      return;
    }
    state.mode = "play";
    state.role = "player";
    state.memberId = memberId();
    state.memberName = String(name || "Player").trim().slice(0, 32) || "Player";
    state.roomId = cleanRoom;
    state.activePlayer = state.memberName;
    state.status = "Joining room...";
    addPlayer(state.memberId, state.memberName);
    bridge("room.join", {
      roomId: state.roomId,
      memberId: state.memberId
    }).then(function () {
      state.status = "Joined " + state.roomId + ". Watch the prompt and shout fast.";
      storageSet(storageKey, JSON.stringify({ roomId: state.roomId, name: state.memberName }));
      sendEvent(eventPlayerJoined, {});
      startPolling();
      startTicker();
      render();
    });
    render();
  }

  function renderShell() {
    document.body.innerHTML = "";
    if (!document.querySelector("link[data-5-second-style]")) {
      const link = document.createElement("link");
      link.rel = "stylesheet";
      link.href = "assets/style.css";
      link.setAttribute("data-5-second-style", "true");
      document.head.appendChild(link);
    }
    const app = el("main", "challengeApp");
    const topbar = el("section", "topbar");
    const brand = el("div", "brand");
    const mark = el("img");
    mark.alt = "";
    mark.src = "assets/challenge-icon.png";
    const titleWrap = el("div");
    titleWrap.appendChild(el("h1", "", "5-Second Challenge"));
    titleWrap.appendChild(el("div", "helper", "Name three things before the room counts down."));
    brand.appendChild(mark);
    brand.appendChild(titleWrap);
    topbar.appendChild(brand);
    topbar.appendChild(el("div", "roomBadge", state.roomId || "Local"));
    app.appendChild(topbar);
    const hero = el("section", "hero");
    const heroImage = el("img", "heroImage");
    heroImage.alt = "";
    heroImage.src = "assets/challenge-header.webp";
    hero.appendChild(heroImage);
    app.appendChild(hero);
    document.body.appendChild(app);
    return app;
  }

  function renderHome(app) {
    const surface = el("section", "surface");
    const modes = el("div", "modeGrid");
    const quick = el("button", "modeButton");
    quick.innerHTML = "<strong>Quick Play</strong><span>One device, pass-and-play scoring.</span>";
    quick.addEventListener("click", startSolo);
    const host = el("button", "modeButton");
    host.innerHTML = "<strong>Host Room</strong><span>Start a nearby room and judge each round.</span>";
    const join = el("button", "modeButton");
    join.innerHTML = "<strong>Join Room</strong><span>Enter a room code and follow the live prompt.</span>";
    modes.appendChild(quick);
    modes.appendChild(host);
    modes.appendChild(join);

    const setup = el("div", "joinGrid");
    const hostName = field("Host name", "host-name", state.memberName || "Host");
    const roomInput = field("Room code", "room-code", state.roomId || "");
    const playerName = field("Player name", "player-name", state.memberName || "Player");
    const hostButton = el("button", "primaryButton", "Create Room");
    hostButton.addEventListener("click", function () {
      startHost(hostName.input.value);
    });
    const joinButton = el("button", "secondaryButton", "Join Room");
    joinButton.addEventListener("click", function () {
      joinRoom(roomInput.input.value, playerName.input.value);
    });
    const hostBox = el("div");
    hostBox.appendChild(hostName.wrap);
    hostBox.appendChild(hostButton);
    const joinBox = el("div");
    joinBox.appendChild(roomInput.wrap);
    joinBox.appendChild(playerName.wrap);
    joinBox.appendChild(joinButton);
    setup.appendChild(hostBox);
    setup.appendChild(joinBox);
    host.addEventListener("click", function () {
      hostName.input.focus();
    });
    join.addEventListener("click", function () {
      roomInput.input.focus();
    });

    surface.appendChild(modes);
    surface.appendChild(setup);
    surface.appendChild(el("p", "status", state.status));
    app.appendChild(surface);
  }

  function field(label, id, value) {
    const wrap = el("label", "field");
    const text = el("span", "", label);
    const input = document.createElement("input");
    input.id = id;
    input.value = value || "";
    wrap.appendChild(text);
    wrap.appendChild(input);
    return { wrap: wrap, input: input };
  }

  function renderGame(app) {
    const surface = el("section", "surface playGrid");
    const promptCard = el("section", "promptCard");
    const left = timeLeft();
    const active = Boolean(state.round && !state.round.result);
    promptCard.appendChild(el("div", "eyebrow", active ? state.round.playerName + "'s turn" : "Ready"));
    promptCard.appendChild(el("p", "prompt", state.round ? state.round.prompt : "Pick a player, draw a prompt, then shout three answers."));
    promptCard.appendChild(el("div", "timer" + (active ? "" : " idle"), active ? String(left) : "5"));
    promptCard.appendChild(el("div", "helper", state.round && state.round.result ? "Result: " + state.round.result : "Judge by ear. No recording, no speech recognition."));

    const controls = el("section", "sidePanel");
    if (state.role !== "player") {
      const selector = document.createElement("select");
      playerNames().forEach(function (name) {
        const option = document.createElement("option");
        option.value = name;
        option.textContent = name;
        option.selected = name === state.activePlayer;
        selector.appendChild(option);
      });
      selector.addEventListener("change", function () {
        state.activePlayer = selector.value;
        render();
      });
      const fieldWrap = el("label", "field");
      fieldWrap.appendChild(el("span", "", "Active player"));
      fieldWrap.appendChild(selector);
      controls.appendChild(fieldWrap);

      const start = el("button", "primaryButton", state.round && !state.round.result ? "Restart Round" : "Start 5 Seconds");
      start.addEventListener("click", beginRound);
      controls.appendChild(start);

      const judgeRow = el("div", "buttonRow");
      const good = el("button", "judgeGood", "Made It");
      const miss = el("button", "judgeMiss", "Missed");
      good.addEventListener("click", function () { judgeRound(true); });
      miss.addEventListener("click", function () { judgeRound(false); });
      judgeRow.appendChild(good);
      judgeRow.appendChild(miss);
      controls.appendChild(judgeRow);

      const reset = el("button", "secondaryButton", "Reset Scores");
      reset.addEventListener("click", resetScores);
      controls.appendChild(reset);
    } else {
      controls.appendChild(el("p", "status", "You are in player view. Watch the prompt, shout answers, and wait for the host to judge."));
    }

    const home = el("button", "secondaryButton", "Back to Modes");
    home.addEventListener("click", function () {
      state.mode = "";
      state.role = "";
      state.round = null;
      stopPolling();
      stopTicker();
      keepScreenOn(false);
      render();
    });
    controls.appendChild(home);
    controls.appendChild(el("p", "status", state.status));
    surface.appendChild(promptCard);
    surface.appendChild(controls);
    app.appendChild(surface);
    app.appendChild(renderScores());
    app.appendChild(renderHistory());
  }

  function renderScores() {
    const panel = el("section", "scoreboard");
    panel.appendChild(el("h2", "", "Scoreboard"));
    scoreRows().forEach(function (row) {
      const item = el("div", "scoreRow");
      item.appendChild(el("div", "scoreName", row.name));
      item.appendChild(el("div", "scoreValue", String(row.score)));
      panel.appendChild(item);
    });
    return panel;
  }

  function renderHistory() {
    const panel = el("section", "history");
    panel.appendChild(el("h2", "", "Recent Rounds"));
    if (!state.history.length) {
      panel.appendChild(el("p", "helper", "No rounds yet."));
      return panel;
    }
    state.history.forEach(function (item) {
      const row = el("div", "historyRow");
      const text = el("div");
      text.appendChild(el("div", "historyPrompt", item.prompt));
      text.appendChild(el("div", "historyMeta", item.playerName + " - " + item.at));
      row.appendChild(text);
      row.appendChild(el("strong", "", item.success ? "+1" : "0"));
      panel.appendChild(row);
    });
    return panel;
  }

  function render() {
    state.now = Date.now();
    const app = renderShell();
    if (state.mode === "play") {
      renderGame(app);
    } else {
      renderHome(app);
    }
  }

  function boot() {
    storageGet(storageKey).then(function (value) {
      if (value) {
        try {
          const saved = JSON.parse(value);
          state.roomId = saved.roomId || "";
          state.memberName = saved.name || "";
        } catch (error) {
          state.roomId = "";
        }
      }
      render();
    });
  }

  window.addEventListener("beforeunload", function () {
    stopPolling();
    stopTicker();
    keepScreenOn(false);
  });

  boot();
})();
