// @wuys/map · core/hash.js
// URL hash sync: encode the active map state into `#map/view=…,lon=…,lat=…,z=…,theme=…`
// so a view is shareable. Debounced writes; one-shot read.

export function attachHashSync({ state, events, prefix = "map" }) {
  let writeTimer = 0;
  const HASH_RE = new RegExp("^#" + prefix + "/");

  function write() {
    if (writeTimer) clearTimeout(writeTimer);
    writeTimer = setTimeout(() => {
      writeTimer = 0;
      try {
        const parts = [
          "view="  + state.view.mode,
          "lon="   + state.nav.lon.toFixed(2),
          "lat="   + state.nav.lat.toFixed(2),
          "z="     + state.nav.zoom.toFixed(2),
          "theme=" + state.theme.id,
        ];
        const next = "#" + prefix + "/" + parts.join(",");
        if (location.hash !== next) history.replaceState(null, "", next);
      } catch (_) { /* sandboxed environments may forbid this */ }
    }, 250);
  }

  function read() {
    try {
      const h = location.hash || "";
      if (!HASH_RE.test(h)) return null;
      const parts = h.slice(2 + prefix.length).split(",");
      const opts = {};
      for (const p of parts) {
        const [k, v] = p.split("=");
        opts[k] = v;
      }
      return opts;
    } catch (_) { return null; }
  }

  // Subscribe nav changes → write.
  events.on("nav:change", write);
  events.on("view:change", write);
  events.on("theme:change", write);

  return { read, write };
}
