(() => {
  "use strict";

  function qs(sel) {
    return document.querySelector(sel);
  }

  function setText(id, text) {
    const el = qs(id);
    if (el) el.textContent = text;
  }

  const leaderboardState = {
    rows: [],
    sortKey: "points",
    sortDir: "desc",
    page: 1,
    pageSize: 10,
    loading: false,
    loaded: false,
    error: null,
  };

  const leaderboardColumns = [
    { key: "rank", label: "Rank", numeric: true },
    { key: "name", label: "Player Name" },
    { key: "points", label: "Points", numeric: true },
    { key: "level", label: "Level", numeric: true },
    { key: "status", label: "Status" },
    { key: "class", label: "Class" },
    { key: "secid", label: "SecID" },
    { key: "kills", label: "Kills", numeric: true },
    { key: "playtime", label: "Playtime", numeric: true },
  ];

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

  function fmtNumber(value) {
    const n = Number(value || 0);
    return Number.isFinite(n) ? n.toLocaleString() : "0";
  }

  function fmtPlaytime(seconds) {
    const total = Number(seconds || 0);
    if (!Number.isFinite(total) || total <= 0) return "0h";
    const hours = Math.floor(total / 3600);
    const minutes = Math.floor((total % 3600) / 60);
    if (hours <= 0) return `${minutes}m`;
    return minutes ? `${hours}h ${minutes}m` : `${hours}h`;
  }

  function normalizeLeaderboardRow(row, index) {
    return {
      originalRank: index + 1,
      name: row.PlayerName || row.CharacterName || row.character_name || "",
      points: Number(row.Points ?? row.TotalPoints ?? 0),
      level: Number(row.Level ?? row.level ?? 0),
      class: row.Class || row.character_class || "",
      secid: row.SecID || row.section_id || "",
      kills: Number(row.Kills ?? row.TotalKills ?? row.total_enemies_killed ?? 0),
      status: (row.Alive === false || row.alive === false) ? "Dead" : "Alive",
      playtime: Number(row.PlayTimeSeconds ?? row.play_time_seconds ?? 0),
    };
  }

  async function fetchHardcoreLeaderboard() {
    leaderboardState.loading = true;
    leaderboardState.error = null;
    renderHardcoreLeaderboard();

    const cacheBucket = Math.floor(Date.now() / 300000);
    const urls = [
      `/generated/hardcore-leaderboard-points.json?v=${cacheBucket}`,
      "/api/hardcore/leaderboard/points",
      "/hardcore/leaderboard/points",
    ];

    let lastError = null;

    for (const url of urls) {
      try {
        const res = await fetch(url, { credentials: "same-origin" });
        if (!res.ok) {
          lastError = new Error(`${url}: HTTP ${res.status}`);
          continue;
        }

        const data = await res.json();
        const rows = Array.isArray(data) ? data : (data.rows || data.characters || []);
        leaderboardState.rows = rows.map(normalizeLeaderboardRow);
        leaderboardState.loaded = true;
        leaderboardState.loading = false;
        leaderboardState.page = 1;
        renderHardcoreLeaderboard();
        return;
      } catch (err) {
        lastError = err;
      }
    }

    leaderboardState.loading = false;
    leaderboardState.error = lastError ? String(lastError.message || lastError) : "Unable to load leaderboard.";
    renderHardcoreLeaderboard();
  }

  function sortedLeaderboardRows() {
    const key = leaderboardState.sortKey;
    const dir = leaderboardState.sortDir === "asc" ? 1 : -1;
    const col = leaderboardColumns.find((c) => c.key === key);
    const numeric = !!col?.numeric;

    return [...leaderboardState.rows].sort((a, b) => {
      let av = key === "rank" ? a.originalRank : a[key];
      let bv = key === "rank" ? b.originalRank : b[key];

      if (numeric) {
        av = Number(av || 0);
        bv = Number(bv || 0);
        return (av - bv) * dir;
      }

      return String(av || "").localeCompare(String(bv || "")) * dir;
    });
  }

  function renderHardcoreLeaderboard() {
    const box = qs("#leaderboard-placeholder");
    if (!box) return;

    if (leaderboardState.loading) {
      box.innerHTML = `<div class="leaderboard-status">Loading Hardcore leaderboard...</div>`;
      return;
    }

    if (leaderboardState.error) {
      box.innerHTML = `<div class="leaderboard-status leaderboard-status--error">${escapeHtml(leaderboardState.error)}</div>`;
      return;
    }

    if (!leaderboardState.loaded) {
      box.innerHTML = `<div class="leaderboard-status">Leaderboard data will load here.</div>`;
      return;
    }

    const rows = sortedLeaderboardRows();
    const pageSize = leaderboardState.pageSize;
    const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
    leaderboardState.page = Math.min(Math.max(1, leaderboardState.page), totalPages);

    const start = (leaderboardState.page - 1) * pageSize;
    const pageRows = rows.slice(start, start + pageSize);

    const head = leaderboardColumns.map((col) => {
      const active = leaderboardState.sortKey === col.key;
      const marker = active ? (leaderboardState.sortDir === "asc" ? " ▲" : " ▼") : "";
      return `<th><button type="button" class="leaderboard-sort" data-sort="${col.key}">${escapeHtml(col.label)}${marker}</button></th>`;
    }).join("");

    const body = pageRows.map((row, idx) => {
      const rank = start + idx + 1;
      return `<tr>
        <td data-label="Rank">${rank}</td>
        <td data-label="Player Name">${escapeHtml(row.name)}</td>
        <td data-label="Points">${fmtNumber(row.points)}</td>
        <td data-label="Level">${fmtNumber(row.level)}</td>
        <td data-label="Status">${escapeHtml(row.status)}</td>
        <td data-label="Class">${escapeHtml(row.class || "—")}</td>
        <td data-label="SecID">${escapeHtml(row.secid || "—")}</td>
        <td data-label="Kills">${fmtNumber(row.kills)}</td>
        <td data-label="Playtime" data-sort-value="${row.playtime}">${escapeHtml(fmtPlaytime(row.playtime))}</td>
      </tr>`;
    }).join("");

    box.innerHTML = `
      <div class="leaderboard-table-wrap">
        <table class="leaderboard-table">
          <thead><tr>${head}</tr></thead>
          <tbody>${body || `<tr><td colspan="9">No Hardcore leaderboard rows yet.</td></tr>`}</tbody>
        </table>
      </div>
      <div class="leaderboard-pager">
        <button type="button" id="leaderboard-prev" ${leaderboardState.page <= 1 ? "disabled" : ""}>Previous</button>
        <span>Page ${leaderboardState.page} of ${totalPages}</span>
        <button type="button" id="leaderboard-next" ${leaderboardState.page >= totalPages ? "disabled" : ""}>Next</button>
      </div>
    `;

    box.querySelectorAll("[data-sort]").forEach((btn) => {
      btn.addEventListener("click", () => {
        const key = btn.getAttribute("data-sort");
        if (leaderboardState.sortKey === key) {
          leaderboardState.sortDir = leaderboardState.sortDir === "asc" ? "desc" : "asc";
        } else {
          leaderboardState.sortKey = key;
          leaderboardState.sortDir = key === "name" || key === "class" || key === "secid" || key === "status" ? "asc" : "desc";
        }
        leaderboardState.page = 1;
        renderHardcoreLeaderboard();
      });
    });

    qs("#leaderboard-prev")?.addEventListener("click", () => {
      leaderboardState.page -= 1;
      renderHardcoreLeaderboard();
    });

    qs("#leaderboard-next")?.addEventListener("click", () => {
      leaderboardState.page += 1;
      renderHardcoreLeaderboard();
    });
  }

  function updateLeaderboards() {
    const mode = qs("#leaderboard-mode")?.value || "hardcore";
    const pageSizeWrap = qs("#leaderboard-page-size-wrap");

    if (pageSizeWrap) pageSizeWrap.hidden = mode !== "hardcore";

    if (mode === "hardcore") {
      if (!leaderboardState.loaded && !leaderboardState.loading) {
        fetchHardcoreLeaderboard();
      } else {
        renderHardcoreLeaderboard();
      }
      return;
    }

    const labels = {
      cmode: "CMode leaderboard placeholder.",
      "hardcore-cmode": "Hardcore CMode leaderboard placeholder.",
    };
    setText("#leaderboard-placeholder", labels[mode] || "Leaderboard data will load here.");
  }

  function updateDrops() {
    const mode = qs("#drops-mode")?.value || "peeps";
    const version = qs("#drops-version")?.value || "v1";
    const versionWrap = qs("#drops-version-wrap");
    const epWrap = qs("#drops-episode-wrap");

    if (!versionWrap || !epWrap) return;

    if (mode === "hardcore") {
      versionWrap.hidden = true;
      epWrap.hidden = false;
      setText("#drops-placeholder", "Hardcore drop table placeholder.");
      return;
    }

    versionWrap.hidden = false;
    epWrap.hidden = version !== "v4";
    setText("#drops-placeholder", `Peeps ${version.toUpperCase()} drop table placeholder.`);
  }

  function updateBestiaryEpisodes(version) {
    const ep = qs("#bestiary-episode");
    if (!ep) return;

    const eps = version === "v4"
      ? [["ep1", "Episode 1"], ["ep2", "Episode 2"], ["ep4", "Episode 4"]]
      : [["ep1", "Episode 1"], ["ep2", "Episode 2"]];

    ep.innerHTML = eps.map(([value, label]) => `<option value="${value}">${label}</option>`).join("");
  }

  function updateBestiary() {
    const version = qs("#bestiary-version")?.value || "v2";
    const epWrap = qs("#bestiary-episode-wrap");
    const bpWrap = qs("#bestiary-bp-wrap");

    if (!epWrap || !bpWrap) return;

    epWrap.hidden = version === "v2";
    bpWrap.hidden = !(version === "v2" || version === "v4");

    if (version === "v3" || version === "v4") {
      updateBestiaryEpisodes(version);
    }

    setText("#bestiary-placeholder", `${version.toUpperCase()} bestiary placeholder.`);
  }

  function bind() {
    qs("#leaderboard-mode")?.addEventListener("change", updateLeaderboards);
    qs("#leaderboard-page-size")?.addEventListener("change", (event) => {
      leaderboardState.pageSize = Number(event.target.value || 10);
      leaderboardState.page = 1;
      renderHardcoreLeaderboard();
    });

    qs("#drops-mode")?.addEventListener("change", updateDrops);
    qs("#drops-version")?.addEventListener("change", updateDrops);

    qs("#bestiary-version")?.addEventListener("change", updateBestiary);
    qs("#bestiary-episode")?.addEventListener("change", updateBestiary);
    qs("#bestiary-bp")?.addEventListener("change", updateBestiary);

    updateLeaderboards();
    updateDrops();
    updateBestiary();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", bind);
  } else {
    bind();
  }
})();
