/* flux_zine_cart.js — universal Zine Cart layer (client-side, no server).
 *
 * Select up to exactly 36 photos from a photo set and generate a canonical-style
 * FLUX zine PDF (via flux_zine_pdf.js). Context-agnostic: configure with
 *   window.FLUX_ZINE_CONFIG = {
 *     contextId : "geotag_<slug>",            // localStorage namespace
 *     photos    : [{id,thumb,large,seq,date,time,camera,address,filename,...}],
 *     zineMeta  : {slug,title,author,date,location,about,stats,qrUrl}
 *   }
 * Reusable later for private projects / full archive by passing a different config.
 *
 * Selection is ephemeral (localStorage per context) and never changes the archive.
 */
(function () {
  "use strict";
  var CFG = window.FLUX_ZINE_CONFIG;
  if (!CFG || !Array.isArray(CFG.photos)) return;

  var LIMIT = 36;
  var KEY = "flux_zine_cart_" + (CFG.contextId || "default");
  var byId = {};
  CFG.photos.forEach(function (p) { byId[p.id] = p; });

  function load() { try { return (JSON.parse(localStorage.getItem(KEY)) || []).filter(function (id) { return byId[id]; }); } catch (e) { return []; } }
  function persist() { try { localStorage.setItem(KEY, JSON.stringify(order)); } catch (e) {} }
  var order = load();

  function count() { return order.length; }
  function has(id) { return order.indexOf(id) >= 0; }
  function add(id) { if (has(id) || order.length >= LIMIT || !byId[id]) return false; order.push(id); persist(); render(); return true; }
  function remove(id) { var i = order.indexOf(id); if (i >= 0) { order.splice(i, 1); persist(); render(); } }
  function toggle(id) { has(id) ? remove(id) : add(id); }
  // FLUX zines are distilled walks, not resequenced photo books: selection is
  // always presented + generated in original walk chronology (sequence number).
  function sorted() {
    return order.slice().sort(function (a, b) {
      return (parseInt((byId[a] || {}).seq, 10) || 0) - (parseInt((byId[b] || {}).seq, 10) || 0);
    });
  }
  function clear() { if (!order.length || confirm("Clear the zine selection?")) { order = []; persist(); render(); } }

  // ── styles (self-contained) ──────────────────────────────────────────────
  var css =
    ".zine-add{margin-top:8px;font-family:'Courier New',monospace;font-size:9px;letter-spacing:.08em;text-transform:uppercase;" +
    "border:1px solid #bbb;background:#fff;color:#111;padding:5px 8px;cursor:pointer;width:100%}" +
    ".zine-add.in{background:#111;color:#fff;border-color:#111}.zine-add:disabled{opacity:.4;cursor:not-allowed}" +
    ".zine-badge{position:fixed;right:16px;bottom:16px;z-index:700;font-family:'Courier New',monospace;font-size:11px;" +
    "letter-spacing:.1em;text-transform:uppercase;background:#111;color:#fff;border:none;padding:12px 16px;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.25)}" +
    ".zine-badge.full{background:#2a6000}" +
    ".zine-panel{position:fixed;inset:0;z-index:710;background:rgba(255,255,255,.97);display:none;flex-direction:column}" +
    ".zine-panel.open{display:flex}" +
    ".zine-head{display:flex;align-items:center;justify-content:space-between;padding:14px 18px;border-bottom:1px solid #e0e0e0;" +
    "font-family:'Courier New',monospace}" +
    ".zine-head b{font-size:13px;letter-spacing:.08em;text-transform:uppercase}" +
    ".zine-list{flex:1;overflow:auto;padding:12px 18px;max-width:760px;margin:0 auto;width:100%}" +
    ".zine-item{display:flex;align-items:center;gap:10px;border-bottom:1px solid #eee;padding:6px 0;font-family:'Courier New',monospace;font-size:11px}" +
    ".zine-item img{width:80px;height:54px;object-fit:cover;border:1px solid #ddd;background:#f5f5f5}" +
    ".zine-item .pos{width:34px;color:#888}.zine-item .cap{flex:1;color:#333}" +
    ".zine-item button{font-family:inherit;font-size:11px;border:1px solid #ccc;background:#fff;cursor:pointer;padding:3px 8px}" +
    ".zine-foot{padding:14px 18px;border-top:1px solid #e0e0e0;display:flex;gap:10px;align-items:center;font-family:'Courier New',monospace;font-size:11px}" +
    ".zine-gen{font-size:12px;letter-spacing:.1em;text-transform:uppercase;background:#111;color:#fff;border:none;padding:11px 18px;cursor:pointer}" +
    ".zine-gen:disabled{background:#ccc;cursor:not-allowed}" +
    ".zine-x{font-family:inherit;font-size:11px;border:1px solid #ccc;background:#fff;cursor:pointer;padding:8px 12px}";
  var st = document.createElement("style"); st.textContent = css; document.head.appendChild(st);

  // ── badge + panel DOM ────────────────────────────────────────────────────
  var badge = document.createElement("button"); badge.className = "zine-badge"; badge.onclick = open;
  document.body.appendChild(badge);
  var panel = document.createElement("div"); panel.className = "zine-panel";
  panel.innerHTML =
    "<div class='zine-head'><b>Zine selection</b><button class='zine-x' id='zine-close'>Close</button></div>" +
    "<div class='zine-list' id='zine-list'></div>" +
    "<div class='zine-foot'><button class='zine-gen' id='zine-gen'>Generate zine PDF</button>" +
    "<button class='zine-x' id='zine-clear'>Clear</button>" +
    "<span id='zine-foot-msg'></span></div>";
  document.body.appendChild(panel);
  panel.querySelector("#zine-close").onclick = close;
  panel.querySelector("#zine-clear").onclick = clear;
  panel.querySelector("#zine-gen").onclick = generate;

  function open() { panel.classList.add("open"); render(); document.body.style.overflow = "hidden"; }
  function close() { panel.classList.remove("open"); document.body.style.overflow = ""; }

  function render() {
    badge.textContent = "Zine  " + count() + " / " + LIMIT;
    badge.classList.toggle("full", count() === LIMIT);
    refreshButtons();
    if (!panel.classList.contains("open")) return;
    var list = panel.querySelector("#zine-list");
    if (!order.length) { list.innerHTML = "<p style='font-family:Courier New,monospace;color:#888;font-size:12px'>No photos selected yet. Use “Add to zine”. The zine is auto-sequenced by walk chronology.</p>"; }
    else {
      list.innerHTML = sorted().map(function (id, i) {
        var p = byId[id];
        var cap = (p.date || "") + (p.time ? " " + p.time : "") + (p.address ? " · " + p.address : "");
        return "<div class='zine-item'><span class='pos'>" + (i + 1) + "</span>" +
          "<img src='" + p.thumb + "'>" +
          "<span class='cap'>" + cap + "</span>" +
          "<button onclick=\"FluxZineCart.remove('" + id + "')\">remove</button></div>";
      }).join("");
    }
    var gen = panel.querySelector("#zine-gen");
    gen.disabled = count() !== LIMIT;
    panel.querySelector("#zine-foot-msg").textContent =
      count() === LIMIT ? "Ready — 36 selected." : (LIMIT - count()) + " more needed (exactly " + LIMIT + ").";
  }

  function refreshButtons() {
    document.querySelectorAll("[data-zine-id]").forEach(function (b) {
      var id = b.getAttribute("data-zine-id"), inCart = has(id), full = count() >= LIMIT;
      b.classList.toggle("in", inCart);
      b.disabled = !inCart && full;
      b.textContent = inCart ? "✓ In zine" : (full ? "Zine full (36)" : "+ Add to zine");
    });
    updateLightboxButton();
  }

  // ── canonical lightbox integration (via additive onRender hook) ───────────
  var _cur = null;
  window.__fluxLightboxOnRender = function (entry) { _cur = entry; updateLightboxButton(); };
  function updateLightboxButton() {
    var actions = document.querySelector("#ar-overlay .ar-ov-actions");
    if (!actions || !_cur) return;
    var btn = document.getElementById("ov-zine-btn");
    if (!btn) {
      btn = document.createElement("button"); btn.id = "ov-zine-btn"; btn.className = "flb-btn";
      btn.addEventListener("click", function () { toggle(btn.getAttribute("data-id")); });
      actions.appendChild(btn);
    }
    btn.setAttribute("data-id", _cur.id);
    var inCart = has(_cur.id), full = count() >= LIMIT;
    btn.disabled = !inCart && full;
    btn.textContent = inCart ? "[✓ IN ZINE]" : (full ? "[ZINE FULL]" : "[+ ADD TO ZINE]");
  }

  // Offline (file://) support: a downloaded export sets window.FLUX_ZINE_IMAGES_URL
  // and ships base64 photo data so the PDF can embed images without a tainting canvas.
  // Loaded lazily (on first Generate) via <script src> — works under file://, unlike
  // fetch. On hosted/live pages the flag is unset, so this is a no-op (full back-compat).
  function ensureZineImages() {
    return new Promise(function (res) {
      if (window.FLUX_ZINE_IMAGES) return res();
      var url = window.FLUX_ZINE_IMAGES_URL;
      if (!url) return res();   // hosted/live: no bundled images → builder uses file paths
      var s = document.createElement("script");
      s.src = url;
      s.onload = function () { res(); };
      s.onerror = function () { res(); };   // proceed; builder falls back to file paths
      document.head.appendChild(s);
    });
  }

  function generate() {
    if (count() !== LIMIT) return;
    if (!window.FluxZinePDF) { alert("Zine PDF module not loaded."); return; }
    var ordered = sorted().map(function (id) { return byId[id]; });   // chronological
    var msg = panel.querySelector("#zine-foot-msg"); msg.textContent = "Generating PDF…";
    ensureZineImages()
      .then(function () { return window.FluxZinePDF.generate(ordered, CFG.zineMeta); })
      .then(function () { msg.textContent = "Downloaded."; })
      .catch(function (e) { msg.textContent = "PDF error: " + (e && e.message || e); });
  }

  window.FluxZineCart = {
    add: add, remove: remove, toggle: toggle, has: has, count: count,
    clear: clear, open: open, close: close,
    generate: generate, refreshButtons: refreshButtons,
  };
  render();
})();
