/* global window */
/* Server-backed storage. Sync cache hydrated from /api/state; writes go through
   the API but also update the cache immediately so the existing prototype code
   (which assumes synchronous storage) keeps working unchanged. */

const MATURITY_LABELS = ['Curious', 'Trying', 'Using', 'Building', 'Compounding'];
const MATURITY_DESCRIPTORS = [
  'Reading about it, not yet daily.',
  'Daily use for personal productivity.',
  'My team relies on it weekly.',
  "We've shipped workflows that wouldn't exist without it.",
  "It's a permanent member of the team.",
];

const QUESTIONS = [
  {
    n: 1,
    prompt: 'A question you wish AI would answer for you this week.',
    hint: 'The real one — the one you keep almost asking out loud at your desk.',
    placeholder: 'I keep wondering...',
  },
  {
    n: 2,
    prompt: 'Where should we focus our energy?',
    hint: 'One bet. Argue for it in two lines.',
    placeholder: 'If it were up to me...',
  },
  {
    n: 3,
    prompt: 'Who in your organization is making bold moves with AI?',
    hint: 'Name + one line on what they\'re doing. Specific beats generous.',
    placeholder: 'Person — what they\'re doing.',
  },
  {
    n: 4,
    prompt: 'The coolest AI thing you did this week?',
    hint: 'This one gets anonymized and voted on. Make it good.',
    placeholder: 'I had it...',
  },
];

// ──────────────────────────────────────────────────────────────
// Bootstrap context — derived from URL + /api/state response
// ──────────────────────────────────────────────────────────────

function readBootContext() {
  const url = new URL(window.location.href);
  const params = url.searchParams;
  const bMatch = url.pathname.match(/^\/b\/([A-Za-z0-9_-]+)/);
  return {
    token: bMatch ? bMatch[1] : null,
    adminSecret: params.get('admin'),
    asParticipant: params.get('as'),
  };
}

function apiUrl(pathname, extra = {}) {
  const u = new URL(pathname, window.location.origin);
  const boot = window.__MB_BOOT_CTX__;
  if (boot.token) u.searchParams.set('token', boot.token);
  if (boot.adminSecret) u.searchParams.set('admin', boot.adminSecret);
  if (boot.asParticipant) u.searchParams.set('as', boot.asParticipant);
  for (const [k, v] of Object.entries(extra)) u.searchParams.set(k, v);
  return u.toString();
}

// ──────────────────────────────────────────────────────────────
// Storage shim — sync cache, async persistence
// ──────────────────────────────────────────────────────────────

const storage = {
  _cache: {},
  get(key, fallback = null) {
    return key in this._cache && this._cache[key] !== null && this._cache[key] !== undefined
      ? this._cache[key]
      : fallback;
  },
  set(key, value) {
    this._cache[key] = value;
    // No generic /api/set route — set() is used only by the prototype's local
    // demo bar, which we replace with explicit submit/vote/admin calls.
    // Kept here for compatibility with code that calls it; effectively no-op
    // for non-API keys (like demo:me).
  },
  del(key) { delete this._cache[key]; },
  clearAll() { this._cache = {}; },
  hydrate(serverState) {
    this._cache = { ...serverState };
  },
};

// Refresh the cache from the server. Called by polling tick.
async function refreshState() {
  try {
    const r = await fetch(apiUrl('/api/state'));
    if (!r.ok) return null;
    const boot = await r.json();
    storage.hydrate(boot.state);
    window.__MB_ADMIN__ = boot.admin;
    window.__MB_ADMIN_SECRET__ = boot.adminSecret;
    window.__MB_ME__ = boot.me;
    window.__MB_PARTICIPANTS__ = boot.participants;
    return boot;
  } catch {
    return null;
  }
}

// ──────────────────────────────────────────────────────────────
// API actions
// ──────────────────────────────────────────────────────────────

async function apiSubmit(data) {
  const r = await fetch(apiUrl('/api/submit'), {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(data),
  });
  if (!r.ok) throw new Error('submit failed: ' + r.status);
  const j = await r.json();
  storage.hydrate(j.state);
  return j;
}

async function apiVote(votes) {
  const r = await fetch(apiUrl('/api/vote'), {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(votes),
  });
  if (!r.ok) throw new Error('vote failed: ' + r.status);
  const j = await r.json();
  storage.hydrate(j.state);
  return j;
}

async function apiAdminReset() {
  const r = await fetch(apiUrl('/admin/reset'), { method: 'POST' });
  const j = await r.json();
  storage.hydrate(j.state);
  return j;
}

async function apiAdminForceClose() {
  const r = await fetch(apiUrl('/admin/close'), { method: 'POST' });
  const j = await r.json();
  storage.hydrate(j.state);
  return j;
}

async function apiAdminForceOpen() {
  const r = await fetch(apiUrl('/admin/open'), { method: 'POST' });
  const j = await r.json();
  storage.hydrate(j.state);
  return j;
}

function adminExportUrl() {
  return apiUrl('/admin/export');
}

// ──────────────────────────────────────────────────────────────
// Helpers
// ──────────────────────────────────────────────────────────────

function getEntryIdForParticipant(pid) {
  const order = storage.get('anonymization:order', []);
  const idx = order.indexOf(pid);
  return idx < 0 ? null : `entry-${idx + 1}`;
}

function getParticipantForEntryId(entryId) {
  const order = storage.get('anonymization:order', []);
  const idx = parseInt(entryId.replace('entry-', ''), 10) - 1;
  const participants = window.PARTICIPANTS || [];
  return participants.find((p) => p.id === order[idx]) || null;
}

// ──────────────────────────────────────────────────────────────
// Expose
// ──────────────────────────────────────────────────────────────

Object.assign(window, {
  MATURITY_LABELS,
  MATURITY_DESCRIPTORS,
  QUESTIONS,
  storage,
  refreshState,
  apiSubmit,
  apiVote,
  apiAdminReset,
  apiAdminForceClose,
  apiAdminForceOpen,
  adminExportUrl,
  getEntryIdForParticipant,
  getParticipantForEntryId,
  readBootContext,
  apiUrl,
});

window.__MB_BOOT_CTX__ = readBootContext();
