// Calm Filters preferences — the canonical FilterPrefs shape, kept in
// localStorage (device-local, no accounts). Mirrors goodnews/filters.py.
const KEY = 'goodnews:prefs';

export function blank() {
  return {
    include_topics: [], include_flavors: [],
    mute_topics: [], mute_flavors: [],
    avoid_terms: [], pauses: [], max_cortisol: null,
    // UI-only: which nav lanes the reader has pinned (keys from /api/lanes).
    // [] means "not customized" — the feed falls back to the default lane set.
    // The backend filter parser ignores unknown keys, so this rides along safely.
    lanes: [],
    // UI-only: which daily items fill the reader's "calm set" (ritual item keys).
    // null = not customized → all eligible items. Rides along like `lanes`.
    ritual: null,
  };
}

export function load() {
  let p;
  try { p = JSON.parse(localStorage.getItem(KEY)) || {}; } catch { p = {}; }
  p = Object.assign(blank(), p);
  const now = Date.now();
  p.pauses = (p.pauses || []).filter((x) => x && x.until && new Date(x.until).getTime() > now);
  return p;
}

export function save(p) {
  localStorage.setItem(KEY, JSON.stringify(p));
}

export function active(p) {
  return !!(p.mute_topics.length || p.mute_flavors.length || p.avoid_terms.length || p.pauses.length);
}

const hours = (h) => new Date(Date.now() + h * 3600e3).toISOString();

export function notToday(p, topic) {
  p.pauses = p.pauses.filter((x) => !(x.kind === 'topic' && x.value === topic));
  p.pauses.push({ kind: 'topic', value: topic, until: hours(24) });
  return p;
}
export function lessLikeThis(p, flavor) {
  p.pauses = p.pauses.filter((x) => !(x.kind === 'flavor' && x.value === flavor));
  p.pauses.push({ kind: 'flavor', value: flavor, until: hours(72) });
  return p;
}
export function alwaysHide(p, topic) {
  if (!p.mute_topics.includes(topic)) p.mute_topics.push(topic);
  return p;
}

// Merge a mood's filter preset over the user's standing prefs into one object.
export function merge(userPrefs, moodFilter = {}) {
  const m = Object.assign(blank(), userPrefs);
  if (moodFilter.include_topics) m.include_topics = moodFilter.include_topics;
  if (moodFilter.include_flavors) m.include_flavors = moodFilter.include_flavors;
  if (moodFilter.max_cortisol != null) m.max_cortisol = moodFilter.max_cortisol;
  return m;
}

// Generic device-local JSON storage (used for session memory: seen / dismissed
// / history), so an account-less reader's choices survive a refresh.
export function loadJSON(key, fallback) {
  try {
    const v = JSON.parse(localStorage.getItem(key));
    return v == null ? fallback : v;
  } catch {
    return fallback;
  }
}
export function saveJSON(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch {
    /* private mode / quota — non-fatal */
  }
}

// "" or "prefs=<encoded json>" for a query string.
export function param(prefs) {
  // Serialize ONLY real filter fields — UI-only keys (lanes, ritual) must not
  // ride in ?prefs= or they churn the feed URL / edge-cache key for no reason.
  const f = {
    include_topics: prefs.include_topics, include_flavors: prefs.include_flavors,
    mute_topics: prefs.mute_topics, mute_flavors: prefs.mute_flavors,
    avoid_terms: prefs.avoid_terms, pauses: prefs.pauses, max_cortisol: prefs.max_cortisol,
  };
  const empty =
    !f.include_topics.length && !f.include_flavors.length &&
    !f.mute_topics.length && !f.mute_flavors.length &&
    !f.avoid_terms.length && !f.pauses.length && f.max_cortisol == null;
  return empty ? '' : 'prefs=' + encodeURIComponent(JSON.stringify(f));
}
