/* API client + live data store ======================================
   Bridges the static frontend to the PHP/MySQL backend under /api.
   Replaces the old localStorage + synthetic-data layer. All dashboard
   numbers now come from RelayLive (fed by /api/data/bootstrap); when the
   warehouse is empty the accessors return zeros/[] so the UI shows real
   empty states instead of fabricated data.
=================================================================== */

/* Base URL = the directory index.html is served from, + "api". Works in a
   subfolder or at the domain root, same-origin (cookies flow automatically). */
const API_BASE = (function(){
  let p = location.pathname;
  if (!p.endsWith('/')) p = p.replace(/[^/]*$/, '');
  return p + 'api';
})();

async function apiFetch(path, opts){
  opts = opts || {};
  const res = await fetch(API_BASE + path, {
    credentials: 'include',
    headers: Object.assign({ 'Content-Type': 'application/json' }, opts.headers || {}),
    method: opts.method || 'GET',
    body: opts.body,
  });
  let data = null;
  try { data = await res.json(); } catch (e) { /* non-JSON */ }
  if (!res.ok) {
    const err = new Error((data && data.error) || ('Request failed (' + res.status + ')'));
    err.status = res.status; err.data = data;
    throw err;
  }
  return data;
}

const RelayAPI = {
  base: API_BASE,
  get:  (p) => apiFetch(p),
  post: (p, b) => apiFetch(p, { method: 'POST', body: JSON.stringify(b || {}) }),
  put:  (p, b) => apiFetch(p, { method: 'PUT', body: JSON.stringify(b || {}) }),
  del:  (p) => apiFetch(p, { method: 'DELETE' }),

  auth: {
    me:     () => apiFetch('/auth/me'),
    login:  (email, password, remember) => apiFetch('/auth/login', { method: 'POST', body: JSON.stringify({ email, password, remember: !!remember }) }),
    logout: () => apiFetch('/auth/logout', { method: 'POST' }),
  },
  users: {
    list:   () => apiFetch('/users').then(r => r.users),
    create: (u) => apiFetch('/users', { method: 'POST', body: JSON.stringify(u) }).then(r => r.user),
    update: (id, u) => apiFetch('/users/' + id, { method: 'PUT', body: JSON.stringify(u) }).then(r => r.user),
    remove: (id) => apiFetch('/users/' + id, { method: 'DELETE' }),
  },
  accounts: {
    list:   () => apiFetch('/accounts').then(r => r.accounts),
    create: (a) => apiFetch('/accounts', { method: 'POST', body: JSON.stringify(a) }).then(r => r.account),
    update: (id, a) => apiFetch('/accounts/' + id, { method: 'PUT', body: JSON.stringify(a) }).then(r => r.account),
    remove: (id) => apiFetch('/accounts/' + id, { method: 'DELETE' }),
  },
  integrations: {
    list:   () => apiFetch('/integrations').then(r => r.integrations),
    create: (it) => apiFetch('/integrations', { method: 'POST', body: JSON.stringify(it) }).then(r => r.integration),
    update: (id, it) => apiFetch('/integrations/' + id, { method: 'PUT', body: JSON.stringify(it) }).then(r => r.integration),
    remove: (id) => apiFetch('/integrations/' + id, { method: 'DELETE' }),
    test:   (id) => apiFetch('/integrations/' + id + '/test', { method: 'POST' }).then(r => r.log),
    sync:   (id) => apiFetch('/integrations/' + id + '/sync', { method: 'POST' }).then(r => r.result),
  },
  audit: {
    list: (filter) => apiFetch('/audit' + (filter && filter !== 'all' ? ('?filter=' + encodeURIComponent(filter)) : '')).then(r => r.audit),
  },
  ingest: (payload) => apiFetch('/ingest', { method: 'POST', body: JSON.stringify(payload) }),
};

/* ---------- Live data store (per account|platform bundle) ---------- */
const RelayLive = (function(){
  const bundles  = {};   // "acc|plat" -> bundle
  const inflight = {};   // "acc|plat|start|end" -> Promise
  const listeners = new Set();
  let _version = 0;
  let _freshness = {};

  const k = (a, p) => a + '|' + (p || 'overview');
  const ymd = (ms) => { const d = new Date(ms); return d.getFullYear() + '-' +
    String(d.getMonth()+1).padStart(2,'0') + '-' + String(d.getDate()).padStart(2,'0'); };
  const notify = () => { _version++; listeners.forEach(fn => fn(_version)); };

  function ensure(acc, plat, dateRange){
    if (!acc) return Promise.resolve();
    plat = plat || 'overview';
    const start = dateRange ? ymd(dateRange.start) : '';
    const end   = dateRange ? ymd(dateRange.end) : '';
    const ik = k(acc, plat) + '|' + start + '|' + end;
    if (inflight[ik]) return inflight[ik];
    const qs = new URLSearchParams({ account: acc, platform: plat });
    if (start) qs.set('start', start);
    if (end)   qs.set('end', end);
    const promise = RelayAPI.get('/data/bootstrap?' + qs.toString())
      .then(b => { bundles[k(acc, plat)] = b; if (b && b.freshness) _freshness = b.freshness; notify(); return b; })
      .catch(e => { bundles[k(acc, plat)] = { _error: e.message, kpis:{}, deltas:{}, spark:{},
        timeseries:[], campaigns:[], creatives:[], alerts:[], platforms:[] }; notify(); })
      .finally(() => { delete inflight[ik]; });
    inflight[ik] = promise;
    return promise;
  }

  return {
    ensure,
    get: (a, p) => bundles[k(a, p)] || null,
    freshness: () => _freshness,
    subscribe: (fn) => { listeners.add(fn); return () => listeners.delete(fn); },
    version: () => _version,
    clearAll: () => { Object.keys(bundles).forEach(key => delete bundles[key]); _freshness = {}; notify(); },
  };
})();

/* Re-render any component when fresh data lands. */
function useDataVersion(){
  const [, setV] = React.useState(RelayLive.version());
  React.useEffect(() => RelayLive.subscribe(setV), []);
  return RelayLive.version();
}

/* Ensure the bundles a view needs are loaded (overview always; + the
   scoped platform). Re-fetches when account, platform or date range change. */
function useEnsureData(acc, plat, dateRange){
  const start = dateRange ? dateRange.start : null;
  const end   = dateRange ? dateRange.end : null;
  React.useEffect(() => {
    RelayLive.ensure(acc, 'overview', dateRange);
    if (plat && plat !== 'overview') RelayLive.ensure(acc, plat, dateRange);
  }, [acc, plat, start, end]);
}

Object.assign(window, { API_BASE, RelayAPI, RelayLive, useDataVersion, useEnsureData });
