// panes/files.js — Surfaces the files.cxllm.io platform data (Providers /
// Edge Functions / Demand / Watcher / Health / File-manager) directly inside
// CxWebApp. All requests go through the C++ backend at /api/files/* which
// injects the PostgREST anon key so the browser never sees the secret.

import { jget, jpost, escapeHtml } from '../lib/api.js';
import { ok, err } from '../lib/ui.js';
import { registerPane } from '../app.js';

const TABS = [
  { id: 'providers',  label: 'Providers',      endpoint: '/mcp_providers?select=*&order=id.asc' },
  { id: 'functions',  label: 'Edge Functions', endpoint: '/platform_functions?select=*&order=slug.asc' },
  { id: 'health',     label: 'Health',         endpoint: '/platform_health?select=*&order=captured_at.desc&limit=20' },
  { id: 'demand',     label: 'Demand Runs',    endpoint: '/demand_runs?select=*&order=received_at.desc&limit=20' },
  { id: 'watcher',    label: 'Watcher Events', endpoint: '/watcher_events?select=*&order=occurred_at.desc&limit=50' },
  { id: 'categories', label: 'File Manager',   endpoint: '/file_manager_categories?select=*&order=category.asc' },
];

let activeTab = 'providers';

const rest     = (path)        => jget(`/api/files${path}`);
const restPost = (path, body)  => jpost(`/api/files${path}`, body, { headers: { Prefer: 'return=minimal' } });

const TPL = `
  <div class="pane-head">
    <div>
      <div class="title">Files · Platform</div>
      <div class="sub">Live providers, edge functions, demand, watcher and health from <code>files.cxllm.io</code>.</div>
    </div>
    <div class="grow"></div>
    <a class="btn btn-secondary" href="https://files.cxllm.io" target="_blank" rel="noopener">Open Studio ↗</a>
    <button class="btn btn-secondary" id="files-refresh">Refresh</button>
  </div>
  <div class="card mb-3">
    <div class="tabs" id="files-tabs">
      ${TABS.map(t => `<button class="tab" data-tab="${t.id}">${escapeHtml(t.label)}</button>`).join('')}
    </div>
  </div>
  <div id="files-body"></div>
`;

function tag(kind, txt) {
  return `<span class="pill ${kind}">${escapeHtml(txt ?? '')}</span>`;
}
function statusPill(s) {
  if (!s) return tag('muted', '—');
  const v = String(s).toLowerCase();
  if (['ok', 'ready', 'healthy', 'success'].includes(v)) return tag('ok', s);
  if (['degraded', 'warn', 'pending', 'running'].includes(v)) return tag('warn', s);
  if (['down', 'failed', 'error'].includes(v)) return tag('err', s);
  return tag('info', s);
}
function ts(s) { return escapeHtml((s || '').replace('T', ' ').slice(0, 19)); }

// ---- renderers ----

function renderProviders(rows) {
  if (!rows.length) return `<div class="card"><div class="muted">No providers configured.</div></div>`;
  return `<div class="grid cols-2">${rows.map(p => `
    <div class="card">
      <div class="card-title"><h2>${escapeHtml(p.name || p.id)}</h2>${statusPill(p.status)}</div>
      <div class="muted mb-2">${escapeHtml(p.description || '')}</div>
      <pre class="mono small">id:      ${escapeHtml(p.id || '')}
model:   ${escapeHtml(p.default_model || '-')}
source:  ${escapeHtml(p.source_file || '')}
base:    ${escapeHtml(p.base_url || '-')}
env:     ${(p.requires_env || []).join(', ') || '(none)'}</pre>
    </div>`).join('')}</div>`;
}

function renderFunctions(rows) {
  if (!rows.length) return `<div class="card"><div class="muted">No edge functions registered.</div></div>`;
  return `<div class="grid cols-2">${rows.map(f => `
    <div class="card">
      <div class="card-title"><h2>${escapeHtml(f.title || f.slug)}</h2>${tag('info', `${f.method || 'GET'} · ${f.runtime || ''}`)}</div>
      <div class="muted mb-2">${escapeHtml(f.description || '')}</div>
      <pre class="mono small">route:   ${escapeHtml(f.route || '')}
source:  ${escapeHtml(f.source_file || '')}
env:     ${(f.requires_env || []).join(', ') || '(none)'}</pre>
    </div>`).join('')}</div>`;
}

function renderHealth(rows) {
  return `
    <div class="card mb-3">
      <div class="row">
        <button class="btn" id="files-capture-health">Capture snapshot</button>
        <span class="muted ml-2">Probes Postgres / MCP / HF / Gitea from the browser, then inserts a row.</span>
      </div>
    </div>
    <div class="card">
      <div class="card-title"><h2>Recent snapshots</h2><span class="muted mono">${rows.length} rows</span></div>
      ${rows.length === 0 ? '<div class="muted">No snapshots yet.</div>' : `
      <table class="table">
        <thead><tr><th>captured</th><th>overall</th><th>ms</th><th>pg</th><th>mcp</th><th>hf</th><th>gitea</th></tr></thead>
        <tbody>${rows.map(r => `
          <tr>
            <td class="mono small">${ts(r.captured_at)}</td>
            <td>${statusPill(r.overall_status)}</td>
            <td class="mono">${r.total_latency_ms ?? ''}</td>
            <td>${r.supabase?.ok ? '✓' : '·'}</td>
            <td>${r.mcp?.ok ? '✓' : '·'}</td>
            <td>${r.huggingface?.ok ? '✓' : '·'}</td>
            <td>${r.gitea?.ok ? '✓' : '·'}</td>
          </tr>`).join('')}
        </tbody>
      </table>`}
    </div>`;
}

function renderDemand(rows) {
  if (!rows.length) return `<div class="card"><div class="muted">No demand runs received. Configure <code>CXCLOUD_MCP_URL</code> in <code>cxai-demand</code>.</div></div>`;
  return `<div class="card">
    <table class="table">
      <thead><tr><th>received</th><th>date</th><th>mode</th><th>designs</th><th>ok</th><th>rej</th><th>quality</th><th>platforms</th></tr></thead>
      <tbody>${rows.map(r => `
        <tr>
          <td class="mono small">${ts(r.received_at)}</td>
          <td>${escapeHtml(r.run_date || '')}</td>
          <td>${r.dry_run ? tag('warn', 'dry') : tag('ok', 'live')}</td>
          <td class="mono">${r.total_designs || 0}</td>
          <td class="mono ok">${r.accepted_designs || 0}</td>
          <td class="mono err">${r.rejected_designs || 0}</td>
          <td class="mono">${r.average_quality_score != null ? Number(r.average_quality_score).toFixed(2) : '—'}</td>
          <td class="muted small">${escapeHtml(Object.keys(r.by_platform || {}).join(', ') || '—')}</td>
        </tr>`).join('')}
      </tbody>
    </table>
  </div>`;
}

function renderWatcher(rows) {
  if (!rows.length) return `<div class="card"><div class="muted">No watcher events yet.</div></div>`;
  return `<div class="card">
    <table class="table">
      <thead><tr><th>when</th><th>kind</th><th>path</th><th>tool</th><th>status</th><th>ms</th></tr></thead>
      <tbody>${rows.map(e => `
        <tr>
          <td class="mono small">${escapeHtml((e.occurred_at || '').replace('T', ' ').slice(11, 19))}</td>
          <td>${tag(e.event_kind === 'created' ? 'ok' : e.event_kind === 'removed' ? 'err' : 'info', e.event_kind)}</td>
          <td class="mono small">${escapeHtml(e.path || '')}</td>
          <td class="muted small">${escapeHtml(e.action_tool || '-')}</td>
          <td>${statusPill(e.status)}</td>
          <td class="mono">${e.latency_ms ?? ''}</td>
        </tr>`).join('')}
      </tbody>
    </table>
  </div>`;
}

function renderCategories(rows) {
  if (!rows.length) return `<div class="card"><div class="muted">No file-manager categories.</div></div>`;
  return `<div class="grid cols-2">${rows.map(c => `
    <div class="card">
      <div class="card-title"><h2>${escapeHtml(c.category || '')}</h2><span class="muted mono">${(c.extensions || []).length} ext</span></div>
      <div class="small">${(c.extensions || []).map(x => `<span class="pill info">.${escapeHtml(x)}</span>`).join(' ')}</div>
    </div>`).join('')}</div>`;
}

const RENDERERS = {
  providers:  renderProviders,
  functions:  renderFunctions,
  health:     renderHealth,
  demand:     renderDemand,
  watcher:    renderWatcher,
  categories: renderCategories,
};

async function loadTab(host, tabId) {
  activeTab = tabId;
  const tab = TABS.find(t => t.id === tabId);
  const body = host.querySelector('#files-body');
  body.innerHTML = `<div class="card"><div class="muted">Loading ${escapeHtml(tab.label)}…</div></div>`;
  host.querySelectorAll('#files-tabs .tab').forEach(b => b.classList.toggle('active', b.dataset.tab === tabId));
  try {
    const data = await rest(tab.endpoint);
    const rows = Array.isArray(data) ? data : [];
    body.innerHTML = RENDERERS[tabId](rows);
    bindActions(host);
  } catch (e) {
    body.innerHTML = `<div class="card">
      <div class="card-title"><h2>Failed to load ${escapeHtml(tab.label)}</h2></div>
      <pre class="mono small">${escapeHtml(e.message || String(e))}</pre>
      <div class="muted small">Confirm <code>CXAI_FILES_UPSTREAM</code> and <code>FILES_ANON_KEY</code> are set on the backend.</div>
    </div>`;
  }
}

function bindActions(host) {
  const capture = host.querySelector('#files-capture-health');
  if (!capture) return;
  capture.onclick = async () => {
    capture.disabled = true; capture.textContent = 'Capturing…';
    const t0 = performance.now();
    const probe = async (name, fn) => {
      const s = performance.now();
      try { const r = await fn(); return { name, ok: !!r, latency_ms: Math.round(performance.now() - s) }; }
      catch { return { name, ok: false, latency_ms: Math.round(performance.now() - s) }; }
    };
    const probes = await Promise.all([
      probe('supabase',    () => rest('/mcp_providers?select=id&limit=1')),
      probe('mcp',         () => fetch('/api/health').then(r => r.ok)),
      probe('huggingface', () => fetch('https://router.huggingface.co/', { mode: 'no-cors' })),
      probe('gitea',       () => fetch('https://cxai-studio.com/git/api/v1/version').then(r => r.ok)),
    ]);
    const okCount = probes.filter(p => p.ok).length;
    const overall = okCount === 4 ? 'ok' : okCount >= 2 ? 'degraded' : 'down';
    try {
      await restPost('/platform_health', {
        overall_status: overall,
        total_latency_ms: Math.round(performance.now() - t0),
        supabase: probes[0], mcp: probes[1], huggingface: probes[2], gitea: probes[3],
        raw: { source: 'cxwebapp', probes },
      });
      ok('Snapshot captured', 'Files');
    } catch (e) {
      err(`Capture failed: ${e.message}`, 'Files');
    }
    await loadTab(host, 'health');
  };
}

registerPane('files', {
  label: 'Files · Platform',
  async init(host) {
    host.innerHTML = TPL;
    host.querySelectorAll('#files-tabs .tab').forEach(b => {
      b.addEventListener('click', () => loadTab(host, b.dataset.tab));
    });
    host.querySelector('#files-refresh').addEventListener('click', () => loadTab(host, activeTab));
    await loadTab(host, activeTab);
  },
  async refresh(host) {
    await loadTab(host, activeTab);
  },
});
