// shared/api.jsx — data loader.
//
// Two modes:
//   1. Live: window.SOM_CONFIG.apiBase is set + ?c=<slug> in URL.
//      Fetches from the Cloudflare Worker (see backend/worker.js).
//   2. Demo: falls back to window.JOY_MOVE hardcoded data.
//      This keeps the prototype working while you set up Airtable.
//
// The dashboard code reads window.CLIENT (populated by init()) which has
// the same shape whether live or demo.

(function () {
  // ─────────────────────────────────────────────
  // Config surface — override in the main HTML via:
  //   <script>window.SOM_CONFIG = { apiBase: '...', adminKey: '...' };</script>
  // ─────────────────────────────────────────────
  window.SOM_CONFIG = Object.assign({
    apiBase: null,      // e.g. 'https://clients.thestateofmotion.com' (Worker URL)
    adminKey: null,     // only set when viewing admin
    slug: null,         // overrides ?c= URL param
  }, window.SOM_CONFIG || {});

  function getParams() {
    const p = new URLSearchParams(window.location.search);
    return {
      slug: window.SOM_CONFIG.slug || p.get('c') || 'demo',
      view: p.get('view') === 'admin' ? 'admin' : 'client',
      adminKey: window.SOM_CONFIG.adminKey || p.get('key') || null,
    };
  }
  window.getPortalParams = getParams;

  async function apiGet(path, headers = {}) {
    if (!window.SOM_CONFIG.apiBase) return null;
    const r = await fetch(window.SOM_CONFIG.apiBase + path, { headers });
    if (!r.ok) throw new Error(`API ${r.status}: ${await r.text()}`);
    return r.json();
  }

  async function apiPost(path, body) {
    if (!window.SOM_CONFIG.apiBase) throw new Error('API not configured — cannot submit');
    const r = await fetch(window.SOM_CONFIG.apiBase + path, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    if (!r.ok) throw new Error(`API ${r.status}: ${await r.text()}`);
    return r.json();
  }

  // ─────────────────────────────────────────────
  // Demo data shaping — map window.JOY_MOVE into the same payload shape
  // the Worker returns, so the UI code is mode-agnostic.
  // ─────────────────────────────────────────────
  function demoPayload() {
    const jm = window.JOY_MOVE;
    const plan = jm.plans.Growth;
    return {
      brand: {
        ...jm.brand,
        slug: 'demo',
        accent: '#4ecdc4',
        logo: null,
        platform: jm.siteHealth.platform,
        fontPair: 'Editorial',
        uptimeMonitorId: null,
      },
      plan: {
        tier: plan.tier, monthly: plan.monthly, hoursIncluded: plan.hoursIncluded,
        responseSLA: plan.responseSLA, overage: plan.overage,
      },
      cycle: jm.cycle,
      siteHealth: jm.siteHealth,
      requests: jm.requests,
      requestCategories: jm.requestCategories,
      activity: jm.activity,
      roadmap: jm.roadmap,
      resources: jm.resources,
      invoices: jm.invoices,
      messageThreads: jm.messageThreads,
      messages: jm.messages,
      _source: 'demo',
    };
  }

  // Fill in the extras a live payload doesn't come back with (category
  // metadata, etc.) so the UI stays consistent.
  function hydrate(live) {
    return {
      ...live,
      requestCategories: (window.JOY_MOVE && window.JOY_MOVE.requestCategories) || [],
      roadmap: live.roadmap || [],
      siteHealth: live.siteHealth || null,
      messages: (live.messageThreads || []).slice(0, 3).map(t => ({
        from: t.with || t.subject,
        preview: (t.messages[t.messages.length - 1] || {}).body || '',
        when: t.updated,
        unread: t.unread,
      })),
      _source: 'live',
    };
  }

  // ─────────────────────────────────────────────
  // Public API
  // ─────────────────────────────────────────────
  window.Portal = {
    config: window.SOM_CONFIG,
    params: getParams,

    async loadClient(slug) {
      const s = slug || getParams().slug;
      if (!window.SOM_CONFIG.apiBase || s === 'demo') {
        return demoPayload();
      }
      try {
        const data = await apiGet(`/api/client/${encodeURIComponent(s)}`);
        return hydrate(data);
      } catch (e) {
        console.warn('[Portal] live load failed, falling back to demo:', e.message);
        return demoPayload();
      }
    },

    async loadRoster() {
      const { adminKey } = getParams();
      if (!window.SOM_CONFIG.apiBase || !adminKey) {
        return window.ADMIN_CLIENTS.map(c => ({ ...c, accent: '#4ecdc4', slug: c.name.toLowerCase().replace(/[^a-z]+/g, '-') }));
      }
      try {
        return await apiGet('/api/admin/roster', { 'x-admin-key': adminKey });
      } catch (e) {
        console.warn('[Portal] roster load failed, falling back to demo:', e.message);
        return window.ADMIN_CLIENTS.map(c => ({ ...c, accent: '#4ecdc4', slug: c.name.toLowerCase().replace(/[^a-z]+/g, '-') }));
      }
    },

    async loadUptime(monitorId) {
      if (!window.SOM_CONFIG.apiBase || !monitorId) {
        // Return a plausible demo shape
        const days = Array.from({ length: 30 }, (_, i) => ({
          day: new Date(Date.now() - (29 - i) * 86400000).toISOString().slice(0, 10),
          status: Math.random() > 0.97 ? 'partial' : 'up',
        }));
        return { uptime30: 99.98, uptimeAll: 99.95, days, avgResponseMs: 284,
          responseTimes: Array.from({ length: 30 }, () => 220 + Math.floor(Math.random() * 180)),
          status: 'up' };
      }
      try {
        return await apiGet(`/api/uptime/${monitorId}`);
      } catch (e) {
        console.warn('[Portal] uptime load failed:', e.message);
        return null;
      }
    },

    async submitRequest(slug, payload) {
      if (!window.SOM_CONFIG.apiBase) {
        // Demo mode: pretend it worked
        return { ok: true, requestId: 'DEMO-' + Math.floor(Math.random() * 900 + 100), demo: true };
      }
      return apiPost(`/api/client/${encodeURIComponent(slug)}/request`, payload);
    },

    async submitReply(slug, requestId, body, opts = {}) {
      if (!window.SOM_CONFIG.apiBase) return { ok: true, demo: true };
      const { adminKey } = getParams();
      const headers = { 'Content-Type': 'application/json' };
      if (opts.role === 'agency' && adminKey) headers['x-admin-key'] = adminKey;
      const r = await fetch(window.SOM_CONFIG.apiBase + `/api/client/${encodeURIComponent(slug)}/reply`, {
        method: 'POST',
        headers,
        body: JSON.stringify({ requestId, body, role: opts.role, fromName: opts.fromName }),
      });
      if (!r.ok) throw new Error(`API ${r.status}: ${await r.text()}`);
      return r.json();
    },

    async submitMessage(slug, payload) {
      if (!window.SOM_CONFIG.apiBase) return { ok: true, demo: true };
      return apiPost(`/api/client/${encodeURIComponent(slug)}/message`, payload);
    },
  };
})();
