<h1 id="gname">Loading…</h1>
<div class="pagebar">
  <a href="/library">← library</a>
  <span id="gcrumb"></span>
</div>
<div id="gbody"><p class="empty">Loading…</p></div>
<script>
"use strict";
const KEY = decodeURIComponent(location.pathname.replace(/^\/library\/game\//, ""));

function chips(label, values) {
  if (!values || !values.length) return "";
  return `<div class="factrow"><b>${esc(label)}</b>
    <span class="chiplist">${values.map(v =>
      `<span class="cue">${esc(v)}</span>`).join("")}</span></div>`;
}

function fact(label, value) {
  return value === null || value === undefined || value === ""
    ? ""
    : `<div class="factrow"><b>${esc(label)}</b> ${esc(value)}</div>`;
}

function players(g) {
  // mirror of _players() in export.py — keep the two in sync
  const lo = g.min_players ?? g.max_players, hi = g.max_players ?? g.min_players;
  if (!lo) return "";
  const range = lo === hi ? `${lo}` : `${lo}–${hi}`;
  const noun = lo === 1 && hi === 1 ? "player" : "players";
  const best = (g.best_player_counts || []).length
    ? ` (best at ${esc(g.best_player_counts.join(", "))})`
    : "";
  return `${range} ${noun}${best}`;
}

function playtime(g) {
  if (!g.playtime && !g.min_playtime) return "";
  if (g.min_playtime && g.max_playtime && g.min_playtime !== g.max_playtime)
    return `${g.min_playtime}–${g.max_playtime} min`;
  return `${g.playtime || g.min_playtime} min`;
}

function localForm(g) {
  const v = (x) => (x === null || x === undefined ? "" : x);
  return `
  <h2>Your notes</h2>
  <div class="card prose">
    <p class="meta">BGG has no entry for this game, so what you type here is
      all it will ever know. Saved to <code>data/local_games.json</code>.</p>
    <form class="editform" id="localform">
      <label>Title <input name="name" value="${esc(v(g.name))}" required></label>
      <label>Year <input name="year" value="${esc(v(g.year))}" inputmode="numeric" size="6"></label>
      <label>Players from <input name="min_players" value="${esc(v(g.min_players))}" size="3"></label>
      <label>to <input name="max_players" value="${esc(v(g.max_players))}" size="3"></label>
      <label>Minutes <input name="playtime" value="${esc(v(g.playtime))}" size="5"></label>
      <label>Publishers <input name="publishers" value="${esc((g.publishers || []).join(", "))}"></label>
      <label>Designers <input name="designers" value="${esc((g.designers || []).join(", "))}"></label>
      <label class="wide">Notes
        <textarea name="description" rows="4">${esc(v(g.description))}</textarea></label>
      <span class="editactions"><button type="submit" class="primary">save</button></span>
    </form>
  </div>`;
}

function wireLocal(g) {
  const form = document.getElementById("localform");
  if (form) form.addEventListener("submit", async e => {
    e.preventDefault();
    const f = Object.fromEntries(new FormData(form).entries());
    const res = await apiPost(`/api/local-game/${encodeURIComponent(KEY)}`, f);
    if (res) {
      showToast("saved — run <b>enrich</b> to fold this into the library");
      refresh();
    }
  });
  const btn = document.getElementById("artbtn");
  const file = document.getElementById("artfile");
  if (btn) btn.addEventListener("click", () => file.click());
  if (file) file.addEventListener("change", async () => {
    if (!file.files.length) return;
    const body = new FormData();
    body.append("file", file.files[0]);
    btn.disabled = true;
    btn.textContent = "uploading…";
    let res = null;
    try {
      res = await fetch(`/api/local-art/${encodeURIComponent(KEY)}`, {method: "POST", body});
    } catch (err) {
      alert("Upload failed: " + err);
    }
    btn.disabled = false;
    if (res && res.ok) {
      showToast("photo saved — run <b>enrich</b> to fold it into the library");
      refresh();
    } else if (res) {
      const detail = await res.json().then(d => d.detail).catch(() => null);
      alert("Upload failed: " + (detail ?? res.statusText));
      refresh();
    }
  });
}

function render(g) {
  document.getElementById("gname").textContent = g.name || "(unnamed)";
  document.title = `${g.name} · bggpipe`;
  const local = g.type === "localgame";
  const rpg = g.type === "rpgitem";
  document.getElementById("gcrumb").innerHTML = [
    g.year ? `<b>${esc(g.year)}</b>` : "",
    local ? `<span class="chip open">not on BGG · local</span>` : "",
    rpg ? `<span class="chip open">RPG · local only</span>` : "",
    g.bgg_id
      ? `<a href="${bggUrl(g.bgg_id, g.type)}" target="_blank" rel="noopener">
           view on ${rpg ? "RPGGeek" : "BGG"} ↗</a>`
      : "",
  ].filter(Boolean).join(" · ");

  const art = g.image
    ? `<img class="gameart" src="${esc(g.image)}" alt="box art for ${esc(g.name)}">`
    : `<div class="gameart noart">${esc((g.name || "?")[0])}</div>`;
  // an off-BGG game has no publisher art and no API to fetch any: the
  // owner's own photo is the only cover it will ever have
  const artAdd = local
    ? `<button id="artbtn" class="artbtn">${g.image ? "replace" : "add"} a photo</button>
       <input id="artfile" type="file" accept=".jpg,.jpeg,.png,.heic" hidden
              aria-label="cover photo for ${esc(g.name)}">`
    : "";

  const dims = g.dims && g.dims.width_in
    ? `${g.dims.width_in} × ${g.dims.length_in} × ${g.dims.depth_in} in`
      + (g.dims.weight_lb ? ` · ${g.dims.weight_lb} lb` : "")
      + (g.dims.source === "unanimous" ? " (all printings agree)" : "")
    : "";
  const facts = [
    fact("players", players(g)),
    fact("playing time", playtime(g)),
    fact("box", dims),
    fact("ages", g.min_age ? `${g.min_age}+` : ""),
    fact("weight", g.weight ? `${g.weight.toFixed(2)} / 5` : ""),
    fact("BGG rank", g.rank || ""),
    fact("BGG rating", g.rating ? g.rating.toFixed(2) : ""),
    fact("owned by", g.users_owned ? `${g.users_owned.toLocaleString()} people` : ""),
    chips("designers", g.designers),
    chips("artists", (g.artists || []).slice(0, 8)),
    chips("publishers", (g.publishers || []).slice(0, 6)),
    chips("categories", g.categories),
    chips("mechanics", g.mechanics),
  ].filter(Boolean).join("");

  const version = g.version
    ? `<h2>Your edition</h2>
       <div class="card prose">
         <div class="factrow"><b>${esc(g.version.name || "—")}</b>
           ${g.version.year ? ` · ${esc(g.version.year)}` : ""}</div>
         ${chips("publishers", g.version.publishers)}
         ${chips("languages", g.version.languages)}
       </div>`
    : `<h2>Your edition</h2>
       <div class="card prose"><p class="meta">No specific edition recorded —
         set one from the <a href="/titles">Titles</a> page if you know it.</p></div>`;

  const boxed = g.stored_in_game
    ? `<h2>Where it lives</h2>
       <div class="card prose"><p>This one has no box of its own — it lives
         inside <a href="/library/game/${encodeURIComponent(g.stored_in_game.key)}">
         ${esc(g.stored_in_game.name)}</a>.</p></div>`
    : g.stored_in
      ? `<h2>Where it lives</h2>
         <div class="card prose"><p class="meta">Stored inside BGG game
           ${esc(g.stored_in)} (not in the library yet — run <b>enrich</b>).</p></div>`
      : "";
  const contains = (g.contains || []).length
    ? `<h2>In this box</h2>
       <div class="card prose"><p>${g.contains.map(c =>
          `<a href="/library/game/${encodeURIComponent(c.key)}">${esc(c.name)}</a>`
        ).join(" · ")}</p></div>`
    : "";
  const photos = (g.photos || []).length
    ? `<h2>Seen on your shelves</h2>
       <div class="card prose"><p>${g.photos.map(p =>
          `<a href="/photos/view/${encodeURIComponent(p)}">${esc(p)}</a>`
        ).join(" · ")}</p></div>`
    : "";

  document.getElementById("gbody").innerHTML = `
    <div class="gamedetail">
      <div class="gameartcol">${art}${artAdd}</div>
      <div class="gamefacts">${facts}</div>
    </div>
    ${local ? localForm(g) : ""}
    ${version}
    ${boxed}
    ${contains}
    ${photos}
    ${g.description && !local ? `<h2>About</h2>
      <div class="card prose"><p class="gdesc">${esc(g.description)}</p></div>` : ""}`;
  wireLocal(g);
}

async function refresh() {
  try {
    render(await fetchJSON(`/api/library/${encodeURIComponent(KEY)}`));
  } catch (err) {
    document.getElementById("gbody").innerHTML =
      `<p class="empty">This game isn't in the library
        (${esc(err.message || err)}) — it may need <b>enrich</b> to run.
        Back to the <a href="/library">library</a>.</p>`;
  }
}
refresh();
</script>
