{% extends "base.html" %}

{% block title %}Admin — Langfuse Lens{% endblock %}
{% block page_title %}<span data-i18n="admin.title">Administration</span>{% endblock %}

{% block content %}
<div class="tabs" id="admin-tabs">
  <button class="tab active" data-tab="tab-users" data-i18n="admin.users">Users</button>
  <button class="tab" data-tab="tab-tokens" data-i18n="admin.apiTokens">API Tokens</button>
  <button class="tab" data-tab="tab-audit" data-i18n="admin.auditLogs">Audit Logs</button>
  <button class="tab" data-tab="tab-system" data-i18n="admin.system">System</button>
  <button class="tab" data-tab="tab-agent-tools" data-i18n="agentTools.title">Agent Tools</button>
</div>

<!-- Users -->
<div class="tab-panel active" id="tab-users">
  <div class="card">
    <div class="card-header">
      <div class="card-title" data-i18n="admin.userManagement">User Management</div>
      <button class="btn btn-sm btn-primary" id="btn-new-user" data-i18n="admin.newUser">+ New User</button>
    </div>
    <div id="users-table">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
  </div>
</div>

<!-- Tokens -->
<div class="tab-panel" id="tab-tokens">
  <div class="card">
    <div class="card-header">
      <div class="card-title" data-i18n="admin.apiTokenManagement">API Token Management</div>
      <div class="btn-group">
        <button class="btn btn-sm btn-primary" id="btn-new-token" data-i18n="admin.newToken">+ New Token</button>
        <button class="btn btn-sm btn-secondary" id="btn-rotate-expiring" data-i18n="admin.rotateExpiring">Rotate Expiring</button>
      </div>
    </div>
    <div id="tokens-table">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
  </div>
</div>

<!-- Audit -->
<div class="tab-panel" id="tab-audit">
  <div class="card">
    <div class="card-header">
      <div class="card-title" data-i18n="admin.auditLogs">Audit Logs</div>
      <div class="flex gap-8 items-center">
        <select class="form-select" id="audit-action" style="width:auto;margin:0;padding:6px 10px;font-size:12px">
          <option value="" data-i18n="admin.allActions">All Actions</option>
        </select>
        <button class="btn btn-sm btn-secondary" id="btn-refresh-audit" data-i18n="common.refresh">Refresh</button>
      </div>
    </div>
    <div id="audit-table">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
    <div id="audit-pagination"></div>
  </div>
</div>

<!-- Agent Tools -->
<div class="tab-panel" id="tab-agent-tools">
  <div class="card mb-20">
    <div class="card-title mb-16" data-i18n="agentTools.runtimeSummary">Runtime Summary</div>
    <div id="at-summary">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
  </div>

  <div class="card mb-20">
    <div class="card-title mb-16" data-i18n="agentTools.presets">Presets</div>
    <div id="at-presets">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
  </div>

  <div class="card">
    <div class="card-title mb-16" data-i18n="agentTools.builtinTools">Built-in Tool Catalog</div>
    <div id="at-builtin">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
  </div>
</div>

<!-- System -->
<div class="tab-panel" id="tab-system">
  <div class="grid-2 gap-20">
    <div class="card">
      <div class="card-title mb-16" data-i18n="admin.systemHealth">System Health</div>
      <div id="system-health">
        <div class="loading-center"><div class="spinner"></div></div>
      </div>
    </div>
    <div class="card">
      <div class="card-title mb-16" data-i18n="admin.configuration">Configuration</div>
      <div class="form-group">
        <label class="form-label" data-i18n="admin.reloadScope">Reload Scope</label>
        <select class="form-select" id="reload-scope" style="max-width:200px">
          <option value="all" data-i18n="admin.all">All</option>
          <option value="runtime" data-i18n="admin.runtime">Runtime</option>
          <option value="prompts" data-i18n="nav.prompts">Prompts</option>
          <option value="integrations" data-i18n="settings.integrations">Integrations</option>
        </select>
      </div>
      <button class="btn btn-primary" id="btn-reload" data-i18n="admin.reloadConfig">Reload Config</button>
      <div id="reload-result" class="pre-wrap mt-16 hidden"></div>
    </div>
  </div>

  <div class="card mt-20">
    <div class="card-title mb-16" data-i18n="admin.availableRoles">Available Roles</div>
    <div id="roles-list">
      <div class="loading-center"><div class="spinner"></div></div>
    </div>
  </div>
</div>
{% endblock %}

{% block scripts %}
<script type="module">
import { api } from '/static/js/api.js';
import { toast, formatDate, timeAgo, statusBadge, showLoading, showEmpty, escapeHtml, openModal, closeModal, initTabs, paginationHtml, t } from '/static/js/common.js';

initTabs(document.querySelector('.content'));

// ===== USERS =====
async function loadUsers() {
  const el = document.getElementById('users-table');
  showLoading(el);
  try {
    const data = await api.get('/api/admin/users');
    const items = data.users || data.items || [];
    if (items.length === 0) { showEmpty(el, t('admin.noUsers')); return; }
    el.innerHTML = `
      <div class="table-wrap"><table>
        <thead><tr><th>${t('admin.email')}</th><th>${t('common.name')}</th><th>${t('admin.roles')}</th><th>${t('common.status')}</th><th>${t('common.created')}</th><th>${t('common.actions')}</th></tr></thead>
        <tbody>
          ${items.map(u => `
            <tr>
              <td class="td-mono">${escapeHtml(u.email)}</td>
              <td>${escapeHtml(u.name)}</td>
              <td>${(u.roles||[]).map(r => `<span class="badge badge-accent">${escapeHtml(r)}</span>`).join(' ')}</td>
              <td>${statusBadge(u.status || 'active')}</td>
              <td class="text-sm text-muted">${timeAgo(u.created_at)}</td>
              <td class="td-actions">
                <button class="btn btn-sm btn-ghost edit-user" data-id="${u.user_id}" data-name="${escapeHtml(u.name)}" data-status="${u.status||'active'}">${t('common.edit')}</button>
                <button class="btn btn-sm btn-ghost edit-roles" data-id="${u.user_id}" data-roles="${(u.roles||[]).join(',')}">${t('admin.roles')}</button>
              </td>
            </tr>
          `).join('')}
        </tbody>
      </table></div>
    `;
    document.querySelectorAll('.edit-user').forEach(el => el.addEventListener('click', () => editUser(el.dataset.id, el.dataset.name, el.dataset.status)));
    document.querySelectorAll('.edit-roles').forEach(el => el.addEventListener('click', () => editRoles(el.dataset.id, el.dataset.roles)));
  } catch (err) { showEmpty(el, err.message); }
}

function editUser(id, name, status) {
  openModal(t('admin.editUser'), `
    <form id="eu-form">
      <div class="form-group"><label class="form-label">${t('common.name')}</label><input class="form-input" id="eu-name" value="${escapeHtml(name)}" /></div>
      <div class="form-group"><label class="form-label">${t('common.status')}</label>
        <select class="form-select" id="eu-status"><option value="active" ${status==='active'?'selected':''}>${t('admin.active')}</option><option value="suspended" ${status==='suspended'?'selected':''}>${t('admin.suspended')}</option></select>
      </div>
      <div class="modal-footer" style="padding:12px 0 0"><button type="submit" class="btn btn-primary">${t('common.update')}</button></div>
    </form>
  `);
  document.getElementById('eu-form')?.addEventListener('submit', async (e) => {
    e.preventDefault();
    try {
      await api.patch(`/api/admin/users/${id}`, { name: document.getElementById('eu-name').value, status: document.getElementById('eu-status').value });
      closeModal(); toast(t('admin.userUpdated'), 'success'); loadUsers();
    } catch (err) { toast(err.message, 'error'); }
  });
}

function editRoles(id, roles) {
  const allRoles = ['viewer','analyst','editor','owner','ops','super_admin'];
  const current = (roles || '').split(',').filter(Boolean);
  openModal(t('admin.updateRoles'), `
    <form id="er-form">
      ${allRoles.map(r => `
        <div class="form-group"><label class="form-label"><input type="checkbox" value="${r}" ${current.includes(r)?'checked':''} class="role-cb" /> ${r}</label></div>
      `).join('')}
      <div class="modal-footer" style="padding:12px 0 0"><button type="submit" class="btn btn-primary">${t('admin.updateRoles')}</button></div>
    </form>
  `);
  document.getElementById('er-form')?.addEventListener('submit', async (e) => {
    e.preventDefault();
    const selected = [...document.querySelectorAll('.role-cb:checked')].map(cb => cb.value);
    try {
      await api.put(`/api/admin/users/${id}/roles`, { roles: selected });
      closeModal(); toast(t('admin.rolesUpdated'), 'success'); loadUsers();
    } catch (err) { toast(err.message, 'error'); }
  });
}

document.getElementById('btn-new-user')?.addEventListener('click', () => {
  openModal(t('admin.createUser'), `
    <form id="nu-form">
      <div class="form-group"><label class="form-label">${t('admin.email')}</label><input class="form-input" id="nu-email" required /></div>
      <div class="form-group"><label class="form-label">${t('common.name')}</label><input class="form-input" id="nu-name" required /></div>
      <div class="form-group"><label class="form-label">${t('admin.roles')}</label><input class="form-input" id="nu-roles" value="viewer" placeholder="viewer,analyst" /></div>
      <div class="modal-footer" style="padding:12px 0 0"><button type="submit" class="btn btn-primary">${t('common.create')}</button></div>
    </form>
  `);
  document.getElementById('nu-form')?.addEventListener('submit', async (e) => {
    e.preventDefault();
    try {
      await api.post('/api/admin/users', {
        email: document.getElementById('nu-email').value,
        name: document.getElementById('nu-name').value,
        roles: document.getElementById('nu-roles').value.split(',').map(s=>s.trim()).filter(Boolean),
      });
      closeModal(); toast(t('admin.userCreated'), 'success'); loadUsers();
    } catch (err) { toast(err.message, 'error'); }
  });
});

// ===== TOKENS =====
async function loadTokens() {
  const el = document.getElementById('tokens-table');
  showLoading(el);
  try {
    const data = await api.get('/api/admin/tokens');
    const items = data.tokens || data.items || [];
    if (items.length === 0) { showEmpty(el, t('admin.noTokens')); return; }
    el.innerHTML = `
      <div class="table-wrap"><table>
        <thead><tr><th>${t('common.name')}</th><th>${t('admin.role')}</th><th>${t('admin.subject')}</th><th>${t('admin.expires')}</th><th>${t('admin.revoked')}</th><th>${t('admin.lastUsed')}</th><th>${t('common.actions')}</th></tr></thead>
        <tbody>
          ${items.map(tk => `
            <tr>
              <td>${escapeHtml(tk.name)}</td>
              <td><span class="badge badge-accent">${escapeHtml(tk.role)}</span></td>
              <td class="text-sm">${escapeHtml(tk.subject || '-')}</td>
              <td class="text-sm text-muted">${tk.expires_at ? formatDate(tk.expires_at) : t('admin.never')}</td>
              <td>${tk.revoked ? statusBadge('suspended') : statusBadge('active')}</td>
              <td class="text-sm text-muted">${timeAgo(tk.last_used_at)}</td>
              <td class="td-actions">
                <button class="btn btn-sm btn-ghost rotate-token" data-id="${tk.token_id}">${t('admin.rotate')}</button>
                <button class="btn btn-sm btn-danger revoke-token" data-id="${tk.token_id}">${t('admin.revoke')}</button>
              </td>
            </tr>
          `).join('')}
        </tbody>
      </table></div>
    `;
    document.querySelectorAll('.rotate-token').forEach(el => el.addEventListener('click', () => rotateToken(el.dataset.id)));
    document.querySelectorAll('.revoke-token').forEach(el => el.addEventListener('click', () => revokeToken(el.dataset.id)));
  } catch (err) { showEmpty(el, err.message); }
}

async function rotateToken(id) {
  try {
    const data = await api.post(`/api/admin/tokens/${id}/rotate`);
    toast(t('admin.tokenRotated'), 'success');
    if (data.new_token || data.token) {
      openModal(t('admin.newTokenCopyNow'), `<div class="pre-wrap" style="word-break:break-all">${escapeHtml(data.new_token || data.token)}</div>`);
    }
    loadTokens();
  } catch (err) { toast(err.message, 'error'); }
}

async function revokeToken(id) {
  if (!confirm(t('admin.revokeConfirm'))) return;
  try { await api.del(`/api/admin/tokens/${id}`); toast(t('admin.tokenRevoked'), 'success'); loadTokens(); }
  catch (err) { toast(err.message, 'error'); }
}

document.getElementById('btn-new-token')?.addEventListener('click', () => {
  openModal(t('admin.createToken'), `
    <form id="nt-form">
      <div class="form-group"><label class="form-label">${t('common.name')}</label><input class="form-input" id="nt-name" required /></div>
      <div class="form-row">
        <div class="form-group"><label class="form-label">${t('admin.role')}</label>
          <select class="form-select" id="nt-role">
            <option value="viewer">${t('admin.viewer')}</option><option value="analyst">${t('admin.analyst')}</option><option value="editor">${t('admin.editor')}</option>
            <option value="owner" selected>${t('admin.owner')}</option><option value="ops">${t('admin.ops')}</option><option value="super_admin">${t('admin.superAdmin')}</option>
          </select>
        </div>
        <div class="form-group"><label class="form-label">${t('admin.expiresDays')}</label><input class="form-input" id="nt-days" type="number" placeholder="e.g. 90" /></div>
      </div>
      <div class="form-group"><label class="form-label">${t('admin.subject')}</label><input class="form-input" id="nt-subject" placeholder="user@example.com" /></div>
      <div class="modal-footer" style="padding:12px 0 0"><button type="submit" class="btn btn-primary">${t('common.create')}</button></div>
    </form>
  `);
  document.getElementById('nt-form')?.addEventListener('submit', async (e) => {
    e.preventDefault();
    try {
      const body = {
        name: document.getElementById('nt-name').value,
        role: document.getElementById('nt-role').value,
        subject: document.getElementById('nt-subject').value,
      };
      const days = document.getElementById('nt-days').value;
      if (days) body.expires_days = parseInt(days);
      const data = await api.post('/api/admin/tokens', body);
      closeModal();
      if (data.token || data.raw_token) {
        openModal(t('admin.newTokenCopyNow'), `<div class="pre-wrap" style="word-break:break-all">${escapeHtml(data.token || data.raw_token)}</div><p class="text-sm text-muted mt-8">${t('admin.tokenNotShownAgain')}</p>`);
      }
      toast(t('admin.tokenCreated'), 'success');
      loadTokens();
    } catch (err) { toast(err.message, 'error'); }
  });
});

document.getElementById('btn-rotate-expiring')?.addEventListener('click', async () => {
  try {
    const data = await api.post('/api/admin/tokens/rotate-expiring');
    toast(t('admin.rotatedCount', { n: data.rotated || 0 }), 'success');
    loadTokens();
  } catch (err) { toast(err.message, 'error'); }
});

// ===== AUDIT LOGS =====
let auditPage = 1;

async function loadAudit() {
  const el = document.getElementById('audit-table');
  showLoading(el);
  const action = document.getElementById('audit-action').value;
  let url = `/api/admin/audit-logs?page=${auditPage}&size=20`;
  if (action) url += `&action=${action}`;

  try {
    const data = await api.get(url);
    const items = data.items || [];
    if (items.length === 0) { showEmpty(el, t('admin.noAuditLogs')); return; }
    el.innerHTML = `
      <div class="table-wrap"><table>
        <thead><tr><th>${t('runs.time')}</th><th>${t('admin.actor')}</th><th>${t('admin.action')}</th><th>${t('admin.resource')}</th><th>${t('runs.detail')}</th></tr></thead>
        <tbody>
          ${items.map(a => `
            <tr>
              <td class="text-sm text-muted">${timeAgo(a.timestamp)}</td>
              <td class="td-mono text-sm">${escapeHtml(a.actor)}</td>
              <td><span class="badge badge-info">${escapeHtml(a.action)}</span></td>
              <td class="text-sm">${escapeHtml(a.resource_type)}/${escapeHtml(a.resource_id?.slice(0,10) || '')}</td>
              <td class="text-sm text-muted truncate">${escapeHtml(JSON.stringify(a.detail||{}).slice(0,60))}</td>
            </tr>
          `).join('')}
        </tbody>
      </table></div>
    `;
    document.getElementById('audit-pagination').innerHTML = paginationHtml(data.page, data.size, data.total);
    document.querySelectorAll('#audit-pagination [data-page]').forEach(el => {
      el.addEventListener('click', () => { const p = parseInt(el.dataset.page); if (p >= 1) { auditPage = p; loadAudit(); } });
    });
  } catch (err) { showEmpty(el, err.message); }
}

document.getElementById('audit-action')?.addEventListener('change', () => { auditPage = 1; loadAudit(); });
document.getElementById('btn-refresh-audit')?.addEventListener('click', loadAudit);

// ===== SYSTEM =====
async function loadSystemHealth() {
  const el = document.getElementById('system-health');
  try {
    const data = await api.get('/api/admin/system/health');
    const entries = Object.entries(data).filter(([k]) => k !== 'ok');
    el.innerHTML = entries.map(([k, v]) => `
      <div class="detail-row">
        <div class="detail-label">${escapeHtml(k)}</div>
        <div class="detail-value">${typeof v === 'object' ? `<pre class="text-sm">${escapeHtml(JSON.stringify(v, null, 2))}</pre>` : escapeHtml(String(v))}</div>
      </div>
    `).join('');
  } catch (err) { el.innerHTML = `<p class="text-muted">${err.message}</p>`; }
}

async function loadRoles() {
  const el = document.getElementById('roles-list');
  try {
    const data = await api.get('/api/admin/roles');
    const roles = data.roles || data || {};
    el.innerHTML = `
      <div class="table-wrap"><table>
        <thead><tr><th>${t('admin.role')}</th><th>${t('admin.level')}</th><th>${t('admin.permissions')}</th></tr></thead>
        <tbody>
          ${Object.entries(roles).map(([name, info]) => `
            <tr>
              <td><span class="badge badge-accent">${escapeHtml(name)}</span></td>
              <td class="td-mono">${info.level ?? '-'}</td>
              <td>${(info.permissions || info.scopes || []).map(p => `<span class="tag">${escapeHtml(p)}</span>`).join(' ')}</td>
            </tr>
          `).join('')}
        </tbody>
      </table></div>
    `;
  } catch (err) { el.innerHTML = `<p class="text-muted">${err.message}</p>`; }
}

document.getElementById('btn-reload')?.addEventListener('click', async () => {
  const result = document.getElementById('reload-result');
  try {
    const data = await api.post('/api/admin/system/reload-config', { scope: document.getElementById('reload-scope').value });
    result.classList.remove('hidden');
    result.textContent = JSON.stringify(data, null, 2);
    toast(t('admin.configReloaded'), 'success');
  } catch (err) {
    result.classList.remove('hidden');
    result.textContent = `${t('common.error')}: ${err.message}`;
    toast(err.message, 'error');
  }
});

// ===== AGENT TOOLS =====
async function loadAgentTools() {
  const summaryEl = document.getElementById('at-summary');
  const presetsEl = document.getElementById('at-presets');
  const builtinEl = document.getElementById('at-builtin');

  try {
    const [catalogData, presetsData] = await Promise.all([
      api.get('/api/langfuse/tools/catalog'),
      api.get('/api/langfuse/tools/presets'),
    ]);

    // Runtime summary
    const runtime = catalogData.data?.runtime || catalogData.runtime || {};
    summaryEl.innerHTML = `
      <div class="grid-2 gap-20">
        <div class="detail-row">
          <div class="detail-label">${t('agentTools.currentProfile')}</div>
          <div class="detail-value"><span class="badge badge-accent">${escapeHtml(runtime.profile || '-')}</span></div>
        </div>
        <div class="detail-row">
          <div class="detail-label">${t('agentTools.currentPreset')}</div>
          <div class="detail-value"><span class="badge badge-info">${escapeHtml(runtime.preset_name || '-')}</span></div>
        </div>
        <div class="detail-row">
          <div class="detail-label">${t('agentTools.mutationAllowed')}</div>
          <div class="detail-value">${runtime.mutation_allowed ? `<span class="badge badge-warning">${t('apiConsole.yes')}</span>` : `<span class="badge badge-default">${t('apiConsole.no')}</span>`}</div>
        </div>
        <div class="detail-row">
          <div class="detail-label">${t('agentTools.toolCount')}</div>
          <div class="detail-value"><span class="badge badge-accent">${runtime.tool_count ?? '-'}</span></div>
        </div>
      </div>
    `;

    // Presets table
    const pData = presetsData.data || presetsData;
    const presetList = pData.presets || [];
    const selectedPreset = pData.selected || pData.selected_preset || '';
    const defaultPreset = pData.default_preset || '';

    if (presetList.length === 0) {
      presetsEl.innerHTML = `<p class="text-muted">${t('common.noData')}</p>`;
    } else {
      presetsEl.innerHTML = `
        <div class="table-wrap"><table>
          <thead><tr>
            <th>${t('agentTools.presetName')}</th>
            <th>${t('agentTools.toolCount')}</th>
            <th>${t('agentTools.mutationAllowed')}</th>
            <th>${t('common.status')}</th>
          </tr></thead>
          <tbody>
            ${presetList.map(p => {
              const name = typeof p === 'string' ? p : (p.name || p.preset_name || '-');
              const tools = typeof p === 'object' ? (p.tool_count ?? p.tools?.length ?? '-') : '-';
              const mutation = typeof p === 'object' ? p.mutation_allowed : null;
              const isDefault = name === defaultPreset;
              const isSelected = name === selectedPreset;
              return `
                <tr>
                  <td class="td-mono">${escapeHtml(name)}</td>
                  <td>${escapeHtml(String(tools))}</td>
                  <td>${mutation === true ? `<span class="badge badge-warning">${t('apiConsole.yes')}</span>` : mutation === false ? `<span class="badge badge-default">${t('apiConsole.no')}</span>` : '-'}</td>
                  <td>
                    ${isDefault ? `<span class="badge badge-info">${t('agentTools.default')}</span> ` : ''}
                    ${isSelected ? `<span class="badge badge-accent">${t('agentTools.selected')}</span>` : ''}
                  </td>
                </tr>
              `;
            }).join('')}
          </tbody>
        </table></div>
      `;
    }

    // Builtin tools catalog
    const builtin = catalogData.data?.builtin || catalogData.builtin || {};
    const builtinTools = builtin.tools || [];
    const builtinReadonly = catalogData.data?.builtin_readonly ?? catalogData.builtin_readonly;

    if (builtinTools.length === 0) {
      builtinEl.innerHTML = `<p class="text-muted">${t('common.noData')}</p>`;
    } else {
      builtinEl.innerHTML = `
        <p class="text-sm text-muted mb-8">${builtinReadonly ? t('agentTools.readonlyNote') : t('agentTools.allTools')} (${builtin.count ?? builtinTools.length})</p>
        <div class="table-wrap"><table>
          <thead><tr>
            <th>${t('agentTools.toolName')}</th>
            <th>${t('agentTools.category')}</th>
            <th>${t('agentTools.description')}</th>
          </tr></thead>
          <tbody>
            ${builtinTools.map(tool => `
              <tr>
                <td class="td-mono text-sm">${escapeHtml(tool.name || tool.tool_name || '-')}</td>
                <td><span class="badge badge-default">${escapeHtml(tool.category || '-')}</span></td>
                <td class="text-sm">${escapeHtml(tool.description || '-')}</td>
              </tr>
            `).join('')}
          </tbody>
        </table></div>
      `;
    }
  } catch (err) {
    summaryEl.innerHTML = `<p class="text-muted">${escapeHtml(err.message)}</p>`;
    presetsEl.innerHTML = '';
    builtinEl.innerHTML = '';
  }
}

// Init all
loadUsers();
loadTokens();
loadAudit();
loadSystemHealth();
loadRoles();
loadAgentTools();
</script>
{% endblock %}
