/* =========================================================
   store.jsx, persistent journey state + ledger model.
   Exposes window.JourneyContext, window.useJourney,
   window.useJourneyStore, and helpers.
   ========================================================= */

const STORAGE_KEY = "klaritee.walk.v1";

const EMPTY = {
  listening:      { signals: {}, note: "" },
  framing:        { frame: null, note: "" },
  envisioning:    { signals: [], note: "" },
  assumptions:    { riskiest: null, note: "" },
  transformation: { scales: {}, touched: false, note: "" },
  crux:           { crux: null, note: "" },
  integration:    { note: "" },
};

function loadState() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    return JSON.parse(raw);
  } catch (e) { return null; }
}

/* ---- completion predicates (the gate on each waypoint) ---- */
const COMPLETE = {
  listening:      (m) => Object.values(m.signals || {}).some((a) => a && a.length),
  framing:        (m) => m.frame != null,
  envisioning:    (m) => (m.signals || []).length > 0,
  assumptions:    (m) => m.riskiest != null,
  transformation: (m) => !!m.touched,
  crux:           (m) => m.crux != null,
  integration:    (m) => (m.note || "").trim().length > 0,
};

function stageComplete(id, marks) {
  const fn = COMPLETE[id];
  return fn ? !!fn(marks[id] || {}) : false;
}

/* ---- count of marks for spine / ledger summaries ---- */
function stageMarkCount(id, m) {
  if (!m) return 0;
  switch (id) {
    case "listening": {
      let n = Object.values(m.signals || {}).filter((a) => a && a.length).length;
      if ((m.note || "").trim()) n++;
      return n;
    }
    case "framing":      return (m.frame != null ? 1 : 0) + ((m.note || "").trim() ? 1 : 0);
    case "envisioning":  return (m.signals || []).length + ((m.note || "").trim() ? 1 : 0);
    case "assumptions":  return (m.riskiest != null ? 1 : 0) + ((m.note || "").trim() ? 1 : 0);
    case "transformation": return (m.touched ? Object.keys(m.scales || {}).length || 1 : 0) + ((m.note || "").trim() ? 1 : 0);
    case "crux":         return (m.crux != null ? 1 : 0) + ((m.note || "").trim() ? 1 : 0);
    case "integration":  return (m.note || "").trim() ? 1 : 0;
    default: return 0;
  }
}

function useJourneyStore() {
  const WPS = window.JOURNEY.waypoints;
  const persisted = loadState();

  const [view, setView] = React.useState(persisted?.view ?? "home"); // 'home' | waypoint index
  const [maxReached, setMaxReached] = React.useState(persisted?.maxReached ?? 0);
  const [marks, setMarks] = React.useState(persisted?.marks ?? EMPTY);
  const [theme, setTheme] = React.useState(persisted?.theme ?? "light");
  const [ledgerOpen, setLedgerOpen] = React.useState(false);

  // persist
  React.useEffect(() => {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify({ view, maxReached, marks, theme }));
    } catch (e) {}
  }, [view, maxReached, marks, theme]);

  // theme on root
  React.useEffect(() => {
    const root = document.documentElement;
    if (theme === "dark") root.classList.add("dark");
    else root.classList.remove("dark");
  }, [theme]);

  const setMark = React.useCallback((stageId, updater) => {
    setMarks((prev) => {
      const stage = prev[stageId] || {};
      const next = typeof updater === "function" ? updater(stage) : { ...stage, ...updater };
      return { ...prev, [stageId]: next };
    });
  }, []);

  const goTo = React.useCallback((target) => {
    // target: 'home' or waypoint index
    if (typeof target === "number") {
      setMaxReached((mr) => Math.max(mr, target));
    }
    setView(target);
    // scroll stage to top
    requestAnimationFrame(() => {
      const s = document.querySelector(".stage");
      if (s) s.scrollTop = 0;
    });
  }, []);

  const reset = React.useCallback(() => {
    setMarks(EMPTY); setMaxReached(0); setView("home"); setLedgerOpen(false);
    try { localStorage.removeItem(STORAGE_KEY); } catch (e) {}
  }, []);

  const value = {
    WPS, view, setView, goTo,
    maxReached, setMaxReached,
    marks, setMark,
    theme, setTheme,
    ledgerOpen, setLedgerOpen,
    reset,
    stageComplete: (id) => stageComplete(id, marks),
    stageMarkCount: (id) => stageMarkCount(id, marks[id]),
    totalMarks: WPS.reduce((sum, w) => sum + stageMarkCount(w.id, marks[w.id]), 0),
  };
  return value;
}

const JourneyContext = React.createContext(null);
const useJourney = () => React.useContext(JourneyContext);

Object.assign(window, {
  JourneyContext, useJourney, useJourneyStore,
  stageComplete, stageMarkCount,
});
