// data.jsx — API client; populates window.ZAMPP_DATA from real endpoints

const API = '/api/v1';

window.ZAMPP_DATA = {
  PROJECTS: [],
  ASSETS: [],
  RECORDERS: [],
  JOBS: [],
  NODES: [],
  USERS: [],
  BINS: [],
  COMMENTS: [],
  ME: null,
};

async function apiFetch(path, opts = {}) {
  const res = await fetch(API + path, {
    credentials: 'include',
    headers: { 'Content-Type': 'application/json', ...(opts.headers || {}) },
    ...opts,
  });
  // 401 from any API call means there's no live session. Bounce to the
  // login screen instead of leaving the app in a half-loaded state.
  // While AUTH_ENABLED=false the server returns a synthetic /auth/me with
  // 200 so this branch never fires; flipping AUTH_ENABLED=true is what
  // activates the redirect end-to-end.
  if (res.status === 401 && !location.pathname.endsWith('/login.html')) {
    location.replace('/login.html');
    throw new Error('Unauthenticated — redirecting to login');
  }
  if (!res.ok) throw new Error(res.status + ' ' + res.statusText);
  return res.json();
}

function fmtDuration(ms) {
  if (!ms) return '—';
  const s = Math.round(ms / 1000);
  const h = Math.floor(s / 3600);
  const m = Math.floor((s % 3600) / 60);
  const sec = s % 60;
  if (h > 0) return h + ':' + String(m).padStart(2, '0') + ':' + String(sec).padStart(2, '0');
  return m + ':' + String(sec).padStart(2, '0');
}

function fmtSize(bytes) {
  if (!bytes) return '—';
  if (bytes >= 1e12) return (bytes / 1e12).toFixed(1) + ' TB';
  if (bytes >= 1e9) return (bytes / 1e9).toFixed(1) + ' GB';
  if (bytes >= 1e6) return Math.round(bytes / 1e6) + ' MB';
  return Math.round(bytes / 1e3) + ' KB';
}

function fmtRelative(iso) {
  if (!iso) return '—';
  const diff = (Date.now() - new Date(iso)) / 1000;
  if (diff < 60) return 'just now';
  if (diff < 3600) return Math.floor(diff / 60) + 'm ago';
  if (diff < 86400) return Math.floor(diff / 3600) + 'h ago';
  return Math.floor(diff / 86400) + 'd ago';
}

const PROJECT_COLORS = ['#5B7CFA', '#2DD4A8', '#FF5B5B', '#F5A623', '#B57CFA', '#6B7280'];
window.PROJECT_COLORS = PROJECT_COLORS;

function normalizeAsset(a, projectMap) {
  return {
    ...a,
    name: a.display_name || a.filename || 'Untitled',
    type: a.media_type || 'video',
    duration: fmtDuration(a.duration_ms),
    size: fmtSize(a.file_size),
    res: a.resolution || '—',
    updated: fmtRelative(a.updated_at),
    project: (projectMap && projectMap[a.project_id]) || '',
    comments: 0,
    progress: 0,
    tc: a.start_tc || null,
    seed: a.id ? a.id.charCodeAt(0) % 6 : 1,
  };
}

function normalizeRecorder(r) {
  let elapsed = '—';
  if (r.status === 'recording' && r.started_at) {
    const s = Math.floor((Date.now() - new Date(r.started_at)) / 1000);
    elapsed = String(Math.floor(s / 3600)).padStart(2, '0') + ':' +
              String(Math.floor((s % 3600) / 60)).padStart(2, '0') + ':' +
              String(s % 60).padStart(2, '0');
  }
  const cfg = r.source_config || {};
  return {
    ...r,
    source: r.source_type || '—',
    url: cfg.url || cfg.address || cfg.srt_url || cfg.rtmp_url || r.source_type || '—',
    codec: r.recording_codec || '—',
    res: r.recording_resolution || '—',
    node: r.node_id ? r.node_id.slice(0, 8) : 'primary',
    elapsed,
    bitrate: '—',
    health: 100,
    audio: false,
  };
}

function normalizeJob(j) {
  const statusMap = { waiting: 'queued', active: 'running', completed: 'done', failed: 'failed' };
  const kindMap = { proxy: 'Proxy', thumbnail: 'Thumbnail', conform: 'Conform', transcode: 'Transcode' };
  const meta = j.metadata || {};
  return {
    ...j,
    status: statusMap[j.status] || j.status,
    kind: kindMap[j.type] || j.type || 'Job',
    asset: j.asset_name || meta.filename || '—',
    eta: '—',
    node: meta.node || '—',
    priority: meta.priority || 'normal',
    error: j.error || null,
    progress: j.progress || 0,
  };
}

async function loadData() {
  const [projectsR, assetsR, recordersR, jobsR, clusterR, usersR, binsR, meR] = await Promise.allSettled([
    apiFetch('/projects'),
    apiFetch('/assets?limit=500'),
    apiFetch('/recorders'),
    apiFetch('/jobs'),
    apiFetch('/cluster'),
    apiFetch('/users'),
    apiFetch('/bins'),
    apiFetch('/auth/me'),
  ]);

  const projectMap = {};
  if (projectsR.status === 'fulfilled') {
    window.ZAMPP_DATA.PROJECTS = (projectsR.value || []).map((p, i) => ({
      ...p,
      color: PROJECT_COLORS[i % PROJECT_COLORS.length],
      assets: 0,
      updated: fmtRelative(p.updated_at),
    }));
    window.ZAMPP_DATA.PROJECTS.forEach(p => { projectMap[p.id] = p.name; });
  }

  if (assetsR.status === 'fulfilled') {
    const raw = assetsR.value;
    const list = Array.isArray(raw) ? raw : (raw.assets || []);
    window.ZAMPP_DATA.ASSETS = list.map(a => normalizeAsset(a, projectMap));
    const counts = {};
    list.forEach(a => { if (a.project_id) counts[a.project_id] = (counts[a.project_id] || 0) + 1; });
    window.ZAMPP_DATA.PROJECTS = window.ZAMPP_DATA.PROJECTS.map(p => ({ ...p, assets: counts[p.id] || 0 }));
  }

  if (recordersR.status === 'fulfilled') {
    window.ZAMPP_DATA.RECORDERS = (recordersR.value || []).map(normalizeRecorder);
  }

  if (jobsR.status === 'fulfilled') {
    window.ZAMPP_DATA.JOBS = (jobsR.value || []).map(normalizeJob);
  }

  if (clusterR.status === 'fulfilled') {
    window.ZAMPP_DATA.NODES = clusterR.value || [];
  }

  if (usersR.status === 'fulfilled') {
    window.ZAMPP_DATA.USERS = (usersR.value || []).map(u => ({
      ...u,
      name: u.display_name || u.username || u.email || 'Unknown',
      initials: (u.display_name || u.username || '?').slice(0, 2).toUpperCase(),
      role: u.role || 'viewer',
      joined: fmtRelative(u.created_at),
      lastSeen: fmtRelative(u.last_seen || u.updated_at),
    }));
  }

  if (binsR.status === 'fulfilled') {
    window.ZAMPP_DATA.BINS = (binsR.value || []).map(b => ({
      ...b,
      count: b.asset_count || 0,
      icon: b.type || 'grid',
    }));
  }

  if (meR.status === 'fulfilled' && meR.value) {
    const me = meR.value;
    const label = me.display_name || me.username || 'User';
    window.ZAMPP_DATA.ME = {
      id:        me.id,
      username:  me.username,
      name:      label,
      initials:  label.slice(0, 2).toUpperCase(),
      role:      me.role || 'viewer',
      // True when the server returned a synthetic user (AUTH_ENABLED=false).
      // Surfaced as a small "auth off" hint in the sidebar so the operator
      // understands why the corner shows the OS user instead of a login.
      synthetic: !!me.synthetic,
    };
  }
}

window.ZAMPP_API = { fetch: apiFetch, loadData, fmtDuration, fmtSize, fmtRelative };
// Library re-renders after mutations: expose normalizeAsset so the screen
// can re-fetch /assets and produce rows with the same shape as the boot load.
window.normalizeAsset = normalizeAsset;
