{% extends "base.html" %}

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

{% block content %}
<div class="card">
  <div class="card-header">
    <div class="card-title" data-i18n="experiments.title">Experiments</div>
    <button class="btn btn-sm btn-primary" id="btn-new" data-i18n="experiments.newExperiment">+ New Experiment</button>
  </div>

  <!-- Filters -->
  <div class="filter-bar" style="display:flex; gap:.75rem; flex-wrap:wrap; padding:.75rem 1rem; border-bottom:1px solid var(--border);">
    <select id="filter-type" class="input" style="width:auto; min-width:140px;">
      <option value="" data-i18n="common.type">Type</option>
      <option value="replay" data-i18n="experiments.replay">Trace Replay</option>
      <option value="ab_test" data-i18n="experiments.abTest">A/B Test</option>
      <option value="eval" data-i18n="experiments.evaluation">Evaluation</option>
      <option value="comparison" data-i18n="experiments.comparison">Comparison</option>
    </select>
    <select id="filter-status" class="input" style="width:auto; min-width:120px;">
      <option value="" data-i18n="common.status">Status</option>
      <option value="created">Created</option>
      <option value="running" data-i18n="experiments.running">Running</option>
      <option value="completed" data-i18n="experiments.completed">Completed</option>
      <option value="failed" data-i18n="experiments.failed">Failed</option>
    </select>
    <button class="btn btn-sm btn-secondary" id="btn-filter" data-i18n="common.refresh">Refresh</button>
  </div>

  <!-- Table -->
  <div id="experiments-table">
    <div class="loading-center"><div class="spinner"></div></div>
  </div>

  <!-- Pagination -->
  <div class="pagination" id="experiments-pagination" style="display:none; padding:.75rem 1rem; border-top:1px solid var(--border);">
    <button class="btn btn-sm" id="btn-prev" data-i18n="common.prev">Prev</button>
    <span id="page-info" class="page-info"></span>
    <button class="btn btn-sm" id="btn-next" data-i18n="common.next">Next</button>
  </div>
</div>

<!-- Create modal -->
<div class="modal-overlay" id="create-overlay" hidden>
  <div class="modal" style="max-width:520px;">
    <div class="modal-header">
      <h2 class="modal-title" data-i18n="experiments.newExperiment">New Experiment</h2>
      <button class="modal-close" id="create-close" aria-label="Close">&times;</button>
    </div>
    <div class="modal-body">
      <div class="form-group">
        <label data-i18n="common.name">Name</label>
        <input type="text" id="create-name" class="input" required maxlength="200" />
      </div>
      <div class="form-group">
        <label data-i18n="common.type">Type</label>
        <select id="create-type" class="input">
          <option value="replay" data-i18n="experiments.replay">Trace Replay</option>
          <option value="ab_test" data-i18n="experiments.abTest">A/B Test</option>
          <option value="eval" data-i18n="experiments.evaluation">Evaluation</option>
          <option value="comparison" data-i18n="experiments.comparison">Comparison</option>
        </select>
      </div>
      <div class="form-group">
        <label data-i18n="datasets.description">Description</label>
        <input type="text" id="create-desc" class="input" maxlength="1000" />
      </div>
      <div class="form-group">
        <label><span data-i18n="experiments.config">Config</span> (JSON)</label>
        <textarea id="create-config" class="input" rows="4" style="font-family:monospace;">{}</textarea>
      </div>
      <div class="form-actions" style="display:flex; gap:.5rem; justify-content:flex-end; margin-top:1rem;">
        <button class="btn btn-secondary" id="create-cancel" data-i18n="common.cancel">Cancel</button>
        <button class="btn btn-primary" id="create-submit" data-i18n="common.create">Create</button>
      </div>
    </div>
  </div>
</div>

<!-- Detail modal -->
<div class="modal-overlay" id="detail-overlay" hidden>
  <div class="modal" style="max-width:800px;">
    <div class="modal-header" style="display:flex; align-items:center; gap:.75rem;">
      <h2 class="modal-title" data-i18n="experiments.results" style="flex:1;">Experiment Results</h2>
      <button class="btn btn-sm btn-secondary" id="btn-export-json" title="Export JSON">JSON</button>
      <button class="btn btn-sm btn-secondary" id="btn-export-csv" title="Export CSV">CSV</button>
      <button class="modal-close" id="detail-close" aria-label="Close">&times;</button>
    </div>
    <div class="modal-body" id="detail-body">
      <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, escapeHtml as esc, t } from '/static/js/common.js';

const PAGE_SIZE = 20;
let currentPage = 0;

const TYPE_I18N = { replay: 'experiments.replay', ab_test: 'experiments.abTest', eval: 'experiments.evaluation', comparison: 'experiments.comparison' };
const STATUS_COLORS = { created: '#888', running: 'var(--accent)', completed: '#2a2', failed: '#c33' };

function typeLabel(type) { return t(TYPE_I18N[type]) || type; }

// --- Load experiments ---
async function loadExperiments() {
  const type = document.getElementById('filter-type').value;
  const status = document.getElementById('filter-status').value;
  const params = new URLSearchParams({ limit: PAGE_SIZE, offset: currentPage * PAGE_SIZE });
  if (type) params.set('experiment_type', type);
  if (status) params.set('status', status);

  const container = document.getElementById('experiments-table');
  let res;
  try {
    res = await api.get('/api/experiments?' + params.toString());
  } catch (err) {
    container.innerHTML = `<div class="empty-state" style="padding:2rem; text-align:center; color:var(--text-secondary);">${esc(err.message || 'Network error')}</div>`;
    document.getElementById('experiments-pagination').style.display = 'none';
    toast(err.message || t('common.error'), 'error');
    return;
  }

  if (!res?.ok || !res.data?.items?.length) {
    container.innerHTML = `<div class="empty-state" style="padding:2rem; text-align:center; color:var(--text-secondary);" data-i18n="experiments.noExperiments">${t('experiments.noExperiments') || 'No experiments yet'}</div>`;
    document.getElementById('experiments-pagination').style.display = 'none';
    return;
  }

  const items = res.data.items;
  const total = res.data.total || 0;
  const totalPages = Math.ceil(total / PAGE_SIZE);

  let html = `<table class="data-table"><thead><tr>
    <th>ID</th>
    <th data-i18n="common.name">${t('common.name') || 'Name'}</th>
    <th data-i18n="common.type">${t('common.type') || 'Type'}</th>
    <th data-i18n="common.status">${t('common.status') || 'Status'}</th>
    <th data-i18n="common.created">${t('common.created') || 'Created'}</th>
    <th data-i18n="common.actions">${t('common.actions') || 'Actions'}</th>
  </tr></thead><tbody>`;

  for (const e of items) {
    const tl = typeLabel(e.experiment_type);
    const statusColor = STATUS_COLORS[e.status] || '#888';
    html += `<tr>
      <td>${e.id}</td>
      <td>${esc(e.name)}</td>
      <td><span class="badge" style="background:var(--bg-tertiary); padding:2px 8px; border-radius:4px; font-size:.85em;">${esc(tl)}</span></td>
      <td><span style="color:${statusColor}; font-weight:500;">${esc(e.status)}</span></td>
      <td style="font-size:.85em;">${esc(e.created_at?.replace('T', ' ').slice(0, 19) || '')}</td>
      <td>
        <button class="btn btn-sm" data-view="${e.id}" data-i18n="common.view">${t('common.view') || 'View'}</button>
        <button class="btn btn-sm btn-danger" data-del="${e.id}" data-i18n="common.delete">${t('common.delete') || 'Delete'}</button>
      </td>
    </tr>`;
  }
  html += '</tbody></table>';
  container.innerHTML = html;

  // Pagination
  const pag = document.getElementById('experiments-pagination');
  pag.style.display = totalPages > 1 ? 'flex' : 'none';
  document.getElementById('page-info').textContent = `${currentPage + 1} / ${totalPages}`;
  document.getElementById('btn-prev').disabled = currentPage === 0;
  document.getElementById('btn-next').disabled = currentPage >= totalPages - 1;

  // Event delegation
  container.querySelectorAll('[data-view]').forEach(btn => {
    btn.onclick = () => showDetail(btn.dataset.view);
  });
  container.querySelectorAll('[data-del]').forEach(btn => {
    btn.onclick = () => deleteExperiment(btn.dataset.del);
  });
}

// --- Detail ---
let currentDetailId = null;

async function showDetail(id) {
  currentDetailId = id;
  document.getElementById('detail-overlay').hidden = false;
  const body = document.getElementById('detail-body');
  body.innerHTML = '<div class="loading-center"><div class="spinner"></div></div>';

  const [expRes, runsRes] = await Promise.all([
    api.get(`/api/experiments/${id}`),
    api.get(`/api/experiments/${id}/runs`),
  ]);

  if (!expRes?.ok) { body.innerHTML = '<p>Error loading experiment</p>'; return; }
  const exp = expRes.data;
  const runs = runsRes?.ok ? (runsRes.data?.items || []) : [];

  let html = `<div style="display:grid; gap:1rem;">`;

  // Info
  html += `<div class="card" style="padding:1rem;">
    <h3 style="margin:0 0 .5rem;">${esc(exp.name)}</h3>
    <div style="display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:.5rem; font-size:.9em;">
      <div><strong>Type:</strong> ${esc(typeLabel(exp.experiment_type))}</div>
      <div><strong>Status:</strong> <span style="color:${STATUS_COLORS[exp.status] || '#888'}">${esc(exp.status)}</span></div>
      <div><strong>Runs:</strong> ${runs.length}</div>
      <div><strong>Created:</strong> ${esc(exp.created_at?.replace('T', ' ').slice(0, 19) || '')}</div>
    </div>
    ${exp.description ? `<p style="margin:.5rem 0 0; color:var(--text-secondary); font-size:.9em;">${esc(exp.description)}</p>` : ''}
  </div>`;

  // Aggregate scores by variant
  const variants = {};
  for (const r of runs) {
    const label = r.variant_label || 'unknown';
    if (!variants[label]) variants[label] = { model: r.model_spec, scores_sum: {}, count: 0, latencies: [] };
    variants[label].count++;
    const scores = r.scores || {};
    for (const [k, v] of Object.entries(scores)) {
      if (k === 'parse_error') continue;
      variants[label].scores_sum[k] = (variants[label].scores_sum[k] || 0) + Number(v || 0);
    }
    if (r.latency_ms != null) variants[label].latencies.push(r.latency_ms);
  }

  const variantEntries = Object.entries(variants);

  if (variantEntries.length) {
    // Collect all score keys
    const allKeys = new Set();
    for (const v of Object.values(variants)) for (const k of Object.keys(v.scores_sum)) allKeys.add(k);
    const scoreKeys = [...allKeys].sort();

    // Table
    html += `<div class="card" style="padding:1rem;">
      <h3 style="margin:0 0 .5rem;" data-i18n="experiments.variants">Variant Comparison</h3>
      <div style="overflow-x:auto;">
      <table class="data-table"><thead><tr>
        <th>Variant</th><th>Model</th><th>Runs</th><th>Avg Latency</th>`;
    for (const k of scoreKeys) html += `<th>${esc(k)}</th>`;
    html += `</tr></thead><tbody>`;

    // Compute averages for chart
    const chartData = [];
    for (const [label, v] of variantEntries) {
      const avgLat = v.latencies.length ? (v.latencies.reduce((a, b) => a + b, 0) / v.latencies.length).toFixed(0) + 'ms' : 'N/A';
      const avgs = {};
      html += `<tr><td><strong>${esc(label)}</strong></td><td style="font-size:.85em;">${esc(v.model)}</td><td>${v.count}</td><td>${avgLat}</td>`;
      for (const k of scoreKeys) {
        const avg = v.count > 0 ? (v.scores_sum[k] || 0) / v.count : 0;
        avgs[k] = avg;
        const color = avg >= 0.7 ? '#2a2' : avg >= 0.4 ? '#c80' : '#c33';
        html += `<td style="color:${color}; font-weight:500;">${avg.toFixed(3)}</td>`;
      }
      html += `</tr>`;
      chartData.push({ label, avgs });
    }
    html += '</tbody></table></div></div>';

    // CSS Bar Chart visualization (U4)
    if (scoreKeys.length && chartData.length > 1) {
      const BAR_COLORS = ['var(--accent)', '#2a9d8f', '#e9c46a', '#f4a261', '#e76f51', '#264653'];
      html += `<div class="card" style="padding:1rem;">
        <h3 style="margin:0 0 .75rem;" data-i18n="experiments.scoreComparison">Score Comparison</h3>
        <div style="display:grid; gap:1rem;">`;
      for (const k of scoreKeys) {
        html += `<div>
          <div style="font-size:.85em; font-weight:500; margin-bottom:.25rem;">${esc(k)}</div>`;
        for (let i = 0; i < chartData.length; i++) {
          const d = chartData[i];
          const val = d.avgs[k] || 0;
          const pct = Math.min(val * 100, 100);
          const color = BAR_COLORS[i % BAR_COLORS.length];
          html += `<div style="display:flex; align-items:center; gap:.5rem; margin-bottom:2px;">
            <span style="font-size:.75em; width:80px; text-align:right; flex-shrink:0; color:var(--text-secondary);">${esc(d.label)}</span>
            <div style="flex:1; background:var(--bg-tertiary); border-radius:3px; height:18px; overflow:hidden;">
              <div style="width:${pct.toFixed(1)}%; height:100%; background:${color}; border-radius:3px; transition:width .3s;"></div>
            </div>
            <span style="font-size:.75em; width:45px; font-weight:500;">${val.toFixed(3)}</span>
          </div>`;
        }
        html += `</div>`;
      }
      html += `</div></div>`;
    }
  }

  // Config (U5 — show experiment config)
  if (exp.config && Object.keys(exp.config).length) {
    html += `<div class="card" style="padding:1rem;">
      <h3 style="margin:0 0 .5rem;" data-i18n="experiments.config">Config</h3>
      <pre style="max-height:200px; overflow:auto; font-size:.8em; background:var(--bg-secondary); padding:.75rem; border-radius:4px;">${esc(JSON.stringify(exp.config, null, 2))}</pre>
    </div>`;
  }

  // Result JSON (if exists)
  if (exp.result && Object.keys(exp.result).length) {
    html += `<div class="card" style="padding:1rem;">
      <h3 style="margin:0 0 .5rem;" data-i18n="experiments.results">Results</h3>
      <pre style="max-height:300px; overflow:auto; font-size:.8em; background:var(--bg-secondary); padding:.75rem; border-radius:4px;">${esc(JSON.stringify(exp.result, null, 2))}</pre>
    </div>`;
  }

  html += '</div>';
  body.innerHTML = html;
}

// --- Export ---
function exportExperiment(fmt) {
  if (!currentDetailId) return;
  window.open(`/api/experiments/${currentDetailId}/export?format=${fmt}`, '_blank');
}

// --- Delete ---
async function deleteExperiment(id) {
  if (!confirm(t('experiments.confirmDelete') || 'Delete this experiment?')) return;
  try {
    await api.del(`/api/experiments/${id}`);
    toast(t('experiments.experimentDeleted') || 'Experiment deleted', 'success');
    loadExperiments();
  } catch (err) {
    toast(err.message || t('common.error'), 'error');
  }
}

// --- Create ---
function openCreate() {
  document.getElementById('create-overlay').hidden = false;
  document.getElementById('create-name').value = '';
  document.getElementById('create-desc').value = '';
  document.getElementById('create-config').value = '{}';
}

async function submitCreate() {
  const name = document.getElementById('create-name').value.trim();
  const type = document.getElementById('create-type').value;
  const desc = document.getElementById('create-desc').value.trim();
  const configRaw = document.getElementById('create-config').value.trim();
  if (!name) return;

  let config = {};
  try { config = JSON.parse(configRaw); } catch { toast('Invalid JSON config', 'error'); return; }

  const btn = document.getElementById('create-submit');
  btn.disabled = true;

  try {
    await api.post('/api/experiments', { name, experiment_type: type, description: desc, config });
    document.getElementById('create-overlay').hidden = true;
    toast(t('experiments.experimentCreated') || 'Experiment created', 'success');
    loadExperiments();
  } catch (e) {
    toast(e.message || t('common.error'), 'error');
  } finally {
    btn.disabled = false;
  }
}

// --- Events ---
document.getElementById('btn-new').onclick = openCreate;
document.getElementById('create-submit').onclick = submitCreate;
document.getElementById('create-cancel').onclick = () => { document.getElementById('create-overlay').hidden = true; };
document.getElementById('create-close').onclick = () => { document.getElementById('create-overlay').hidden = true; };
document.getElementById('detail-close').onclick = () => { document.getElementById('detail-overlay').hidden = true; currentDetailId = null; };
document.getElementById('btn-export-json').onclick = () => exportExperiment('json');
document.getElementById('btn-export-csv').onclick = () => exportExperiment('csv');
document.getElementById('btn-filter').onclick = () => { currentPage = 0; loadExperiments(); };
document.getElementById('btn-prev').onclick = () => { if (currentPage > 0) { currentPage--; loadExperiments(); } };
document.getElementById('btn-next').onclick = () => { currentPage++; loadExperiments(); };

// Overlay close on click
document.getElementById('create-overlay').onclick = (e) => { if (e.target.id === 'create-overlay') e.target.hidden = true; };
document.getElementById('detail-overlay').onclick = (e) => { if (e.target.id === 'detail-overlay') { e.target.hidden = true; currentDetailId = null; } };

// Initial load
loadExperiments();
</script>
{% endblock %}
