(function () {
  const protocol = "localchat.activity.v1";
  const eventParticipantEntered = "participant.entered";
  const eventLotteryDrawn = "lottery.drawn";
  const lotteryAlgorithm = "fnv1a32-lcg-fisher-yates-v1";
  const state = {
    role: "",
    roomId: "",
    memberId: "",
    memberName: "",
    cursor: 0,
    participants: {},
    lottery: null,
    pollTimer: 0,
    status: ""
  };

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

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

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

  function hash32(value) {
    let hash = 2166136261;
    const text = String(value || "");
    for (let i = 0; i < text.length; i += 1) {
      hash ^= text.charCodeAt(i);
      hash = Math.imul(hash, 16777619);
    }
    return hash >>> 0;
  }

  function seededRandom(seed) {
    let stateValue = hash32(seed) || 1;
    return function () {
      stateValue = Math.imul(1664525, stateValue) + 1013904223;
      return (stateValue >>> 0) / 4294967296;
    };
  }

  function seededShuffle(items, seed) {
    const random = seededRandom(seed);
    const copy = items.slice();
    for (let index = copy.length - 1; index > 0; index -= 1) {
      const swap = Math.floor(random() * (index + 1));
      const temp = copy[index];
      copy[index] = copy[swap];
      copy[swap] = temp;
    }
    return copy;
  }

  function parseManualCandidates(source) {
    const seen = {};
    return String(source || "")
      .split("\n")
      .map(function (item) { return item.trim(); })
      .filter(Boolean)
      .slice(0, 80)
      .map(function (name, index) {
        return {
          id: safeId("manual-" + hash32(name + ":" + index).toString(36), "manual-" + index),
          name: name.slice(0, 40)
        };
      })
      .filter(function (candidate) {
        if (seen[candidate.id]) {
          return false;
        }
        seen[candidate.id] = true;
        return true;
      });
  }

  function upsertParticipant(memberId, memberName) {
    const id = safeId(memberId, "");
    if (!id) {
      return;
    }
    state.participants[id] = {
      id: id,
      name: String(memberName || "Guest").trim().slice(0, 40) || "Guest"
    };
  }

  function participantList() {
    return Object.keys(state.participants)
      .sort()
      .map(function (id) { return state.participants[id]; });
  }

  function sendEvent(event, extra) {
    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: "activity.event",
      payload: payload
    });
  }

  function applyPayload(payload) {
    if (!payload || payload.protocol !== protocol) {
      return;
    }
    if (payload.event === eventParticipantEntered) {
      upsertParticipant(payload.memberId, payload.memberName);
    }
    if (payload.event === eventLotteryDrawn) {
      state.lottery = {
        lotteryId: payload.lotteryId,
        title: payload.title || "Lucky Draw",
        seed: payload.seed || "",
        algorithm: payload.algorithm || lotteryAlgorithm,
        candidateCount: Number(payload.candidateCount || 0),
        winners: Array.isArray(payload.winners) ? payload.winners : []
      };
    }
  }

  function pollRoom() {
    if (!state.roomId) {
      return;
    }
    bridge("room.poll", {
      roomId: state.roomId,
      memberId: state.memberId,
      since: state.cursor,
      limit: 50
    }).then(function (result) {
      const messages = Array.isArray(result.messages) ? result.messages : [];
      messages.forEach(function (message) {
        applyPayload(message.payload);
      });
      state.cursor = Number(result.nextSince || result.nextCursor || state.cursor || 0);
      render();
    });
  }

  function startPolling() {
    if (state.pollTimer) {
      clearInterval(state.pollTimer);
    }
    state.pollTimer = setInterval(pollRoom, 1200);
    pollRoom();
  }

  function beginHost() {
    state.role = "host";
    state.roomId = newRoomId();
    state.memberName = "Host";
    bridge("ui.setKeepScreenOn", true);
    bridge("room.create", {
      roomId: state.roomId,
      memberId: state.memberId
    }).then(function () {
      state.status = "Room is live";
      startPolling();
      render();
    });
  }

  function beginParticipant(roomId, name) {
    state.role = "participant";
    state.roomId = safeId(roomId, "DRAW-0000").slice(0, 40);
    state.memberName = String(name || "Guest").trim().slice(0, 40) || "Guest";
    storageSet("lucky-draw-name", state.memberName);
    bridge("room.join", {
      roomId: state.roomId,
      memberId: state.memberId
    }).then(function () {
      state.status = "Joined " + state.roomId;
      startPolling();
      return sendEvent(eventParticipantEntered, {});
    }).then(function () {
      render();
    });
  }

  function drawLottery(form) {
    const title = String(form.elements.namedItem("title").value || "").trim().slice(0, 80) || "Lucky Draw";
    const seedInput = String(form.elements.namedItem("seed").value || "").trim().slice(0, 80);
    const requestedWinnerCount = Number(form.elements.namedItem("winnerCount").value || 1);
    const manualCandidates = parseManualCandidates(form.elements.namedItem("manualCandidates").value);
    const candidatesById = {};
    participantList().forEach(function (candidate) {
      candidatesById[candidate.id] = candidate;
    });
    manualCandidates.forEach(function (candidate) {
      candidatesById[candidate.id] = candidate;
    });
    const candidates = Object.keys(candidatesById).sort().map(function (id) {
      return candidatesById[id];
    });
    if (!candidates.length) {
      state.status = "No candidates";
      render();
      return;
    }
    const safeWinnerCount = Number.isFinite(requestedWinnerCount) ? requestedWinnerCount : 1;
    const winnerCount = Math.max(1, Math.min(10, safeWinnerCount, candidates.length));
    const lotteryId = "lottery-" + Date.now();
    const seed = seedInput || lotteryId;
    const winners = seededShuffle(candidates, seed).slice(0, winnerCount);
    state.lottery = {
      lotteryId: lotteryId,
      title: title,
      seed: seed,
      algorithm: lotteryAlgorithm,
      candidateCount: candidates.length,
      winners: winners
    };
    sendEvent(eventLotteryDrawn, {
      lotteryId: lotteryId,
      title: title,
      seed: seed,
      algorithm: lotteryAlgorithm,
      candidateCount: candidates.length,
      winners: winners
    }).then(function () {
      state.status = "Winners drawn";
      bridge("ui.showToast", { message: "Winners drawn" });
      render();
    });
  }

  function renderShell(content) {
    document.body.innerHTML = "";
    if (!document.querySelector("link[data-lucky-draw]")) {
      const link = document.createElement("link");
      link.rel = "stylesheet";
      link.href = "assets/style.css";
      link.dataset.luckyDraw = "true";
      document.head.appendChild(link);
    }
    const app = el("main", "app");
    const topbar = el("header", "topbar");
    const brand = el("div", "brand");
    const mark = el("img");
    mark.src = "assets/lucky-draw-icon.png";
    mark.alt = "";
    brand.appendChild(mark);
    brand.appendChild(el("h1", "", "Lucky Draw"));
    topbar.appendChild(brand);
    if (state.roomId) {
      topbar.appendChild(el("div", "roomCode", state.roomId));
    }
    app.appendChild(topbar);
    const hero = el("section", "hero");
    const heroImage = el("img", "heroImage");
    heroImage.src = "assets/lucky-draw-header.webp";
    heroImage.alt = "";
    hero.appendChild(heroImage);
    app.appendChild(hero);
    app.appendChild(content);
    document.body.appendChild(app);
  }

  function renderStart() {
    const box = el("section", "surface");
    const grid = el("div", "modeGrid");
    const host = el("button", "modeButton");
    host.type = "button";
    host.innerHTML = "<strong>Host draw</strong><span>Collect names and run a fair seeded draw.</span>";
    host.addEventListener("click", beginHost);
    const join = el("form", "joinRow");
    join.innerHTML = [
      "<label class=\"field\"><span>Room code</span><input name=\"room\" maxlength=\"40\" autocomplete=\"off\"></label>",
      "<label class=\"field\"><span>Name</span><input name=\"name\" maxlength=\"40\" autocomplete=\"name\"></label>",
      "<button class=\"primaryButton\" type=\"submit\">Join draw</button>"
    ].join("");
    join.addEventListener("submit", function (event) {
      event.preventDefault();
      beginParticipant(
        join.elements.namedItem("room").value,
        join.elements.namedItem("name").value
      );
    });
    grid.appendChild(host);
    grid.appendChild(join);
    box.appendChild(grid);
    renderShell(box);
  }

  function renderHost() {
    const box = el("section", "surface");
    const grid = el("div", "hostGrid");
    const form = el("form", "panel");
    form.innerHTML = [
      "<h2>Draw setup</h2>",
      "<label class=\"field\"><span>Prize</span><input name=\"title\" maxlength=\"80\" value=\"Lucky Draw\"></label>",
      "<label class=\"field\"><span>Winners</span><input name=\"winnerCount\" type=\"number\" min=\"1\" max=\"10\" value=\"1\"></label>",
      "<label class=\"field\"><span>Seed</span><input name=\"seed\" maxlength=\"80\" placeholder=\"optional\"></label>",
      "<label class=\"field\"><span>Manual candidates</span><textarea name=\"manualCandidates\" placeholder=\"one name per line\"></textarea></label>",
      "<button class=\"primaryButton\" type=\"submit\">Draw Winners</button>"
    ].join("");
    form.addEventListener("submit", function (event) {
      event.preventDefault();
      drawLottery(form);
    });
    const live = el("div", "panel");
    live.appendChild(renderCandidatePanel());
    live.appendChild(renderLotteryResult());
    grid.appendChild(form);
    grid.appendChild(live);
    box.appendChild(grid);
    if (state.status) {
      box.appendChild(el("div", "status", state.status));
    }
    renderShell(box);
  }

  function renderParticipant() {
    const box = el("section", "surface");
    const panel = el("div", "panel");
    panel.appendChild(el("h2", "", "Draw room"));
    panel.appendChild(el("p", "muted", "Waiting for the host to draw winners."));
    panel.appendChild(renderLotteryResult());
    box.appendChild(panel);
    if (state.status) {
      box.appendChild(el("div", "status", state.status));
    }
    renderShell(box);
  }

  function renderCandidatePanel() {
    const panel = el("div");
    const candidates = participantList();
    panel.appendChild(el("h2", "", "Candidates"));
    panel.appendChild(el("p", "finePrint", String(candidates.length) + " joined"));
    const list = el("div", "chipList");
    candidates.slice(0, 24).forEach(function (candidate) {
      list.appendChild(el("span", "chip", candidate.name));
    });
    if (!candidates.length) {
      list.appendChild(el("span", "chip muted", "Waiting"));
    }
    panel.appendChild(list);
    return panel;
  }

  function renderLotteryResult() {
    const panel = el("div");
    if (!state.lottery) {
      panel.appendChild(el("div", "status", "No lottery result"));
      return panel;
    }
    panel.appendChild(el("h2", "", state.lottery.title));
    panel.appendChild(
      el(
        "p",
        "finePrint",
        String(state.lottery.candidateCount) + " candidates · seed " + state.lottery.seed
      )
    );
    const list = el("ol", "winnerList");
    state.lottery.winners.forEach(function (winner) {
      list.appendChild(el("li", "", winner.name || "Winner"));
    });
    panel.appendChild(list);
    return panel;
  }

  function render() {
    if (!state.role) {
      renderStart();
    } else if (state.role === "host") {
      renderHost();
    } else {
      renderParticipant();
    }
  }

  storageGet("lucky-draw-member").then(function (memberId) {
    state.memberId = safeId(memberId, "");
    if (!state.memberId) {
      state.memberId = newMemberId();
      storageSet("lucky-draw-member", state.memberId);
    }
    return storageGet("lucky-draw-name");
  }).then(function (name) {
    state.memberName = String(name || "").slice(0, 40);
    render();
  });
})();
