<% const displayCompanionVersion = (value) => { const match = /^(\d+\.\d+\.\d+)-experimental\.(\d+)$/i.exec(String(value || '')); return match ? `${match[1]} · Experimental release ${match[2]}` : String(value || 'Unknown version'); }; %>
<section class="card transcription-overview" data-transcription-admin>
  <div class="section-header">
    <%- include("../../../src/web/views/partials/page-header", {
      eyebrow: "Experimental companion",
      pageTitle: "Lumi Transcription",
      description: "Server-hosted speech recognition for selected OBS sources, managed through one Lumi Companion application."
    }) %>
    <span class="status-indicator <%= providerHealth.healthy ? 'status-success' : 'status-warning' %>">
      <%= providerHealth.healthy ? 'Inference ready' : 'Setup required' %>
    </span>
  </div>
  <div class="callout warning">
    <strong>Live Twitch delivery is not accepted yet</strong>
    <p>The native OBS 31+ caption path still needs target-machine validation. Lumi will not present a local simulated caption as live Twitch success.</p>
  </div>
</section>

<section class="card setup-path" aria-labelledby="setup-title" data-transcription-admin>
  <div class="section-header">
    <div><span class="eyebrow">First usable path</span><h2 id="setup-title">Setup progress</h2><p class="hint">Complete one clear step at a time. Existing server administration remains in Lumi; streaming-computer controls remain in Companion.</p></div>
  </div>
  <ol>
    <li class="<%= devices.length ? 'is-complete' : 'is-current' %>"><strong>Download and pair Companion</strong><span>Create a short-lived, single-use package for the streaming computer.</span></li>
    <li class="<%= devices.some((device) => device.metadata?.bridge_installed) ? 'is-complete' : devices.length ? 'is-current' : '' %>"><strong>Install the OBS integration</strong><span><%= devices.some((device) => device.metadata?.bridge_installed) ? 'A paired Companion has verified its managed OBS bridge installation.' : 'Companion owns installation and repair; the bridge has no separate settings.' %></span></li>
    <li class="<%= providerHealth.model_ready ? 'is-complete' : '' %>"><strong>Load and benchmark a model</strong><span>Small English is the recommended starting point.</span></li>
    <li class="<%= devices.some((device) => device.metadata?.path_test_valid) ? 'is-complete' : '' %>"><strong>Select and test a microphone</strong><span><%= devices.some((device) => device.metadata?.path_test_valid) ? 'The saved voice-free path check is still valid for the current configuration.' : 'Run the short voice-free path check once after setup or a relevant configuration change.' %></span></li>
  </ol>
  <div class="inline-actions">
    <button class="button" type="button" data-create-pairing>Download Companion</button>
    <a class="button subtle" href="#speech-models">Review speech models</a>
  </div>
  <p class="hint" role="status" aria-live="polite" data-status></p>
</section>

<div class="transcription-grid" data-transcription-admin>
  <section class="card" aria-labelledby="runtime-title">
    <div class="section-header"><div><span class="eyebrow">Lumi host</span><h2 id="runtime-title">Inference health</h2><p class="hint">Speech recognition runs on the Lumi server, never on the streaming computer.</p></div></div>
    <div class="dashboard-metric-grid transcription-metrics">
      <div><span>Provider</span><strong>whisper.cpp <%= runtimeManifest.tested_version %></strong></div>
      <div><span>Worker</span><strong><%= providerHealth.state %></strong></div>
      <div><span>Selected model</span><strong><%= providerHealth.model ? providerHealth.model + (providerHealth.model_ready ? '' : ' · not ready') : 'Not loaded' %></strong></div>
      <div><span>Active sessions</span><strong><%= providerHealth.sessions || 0 %></strong></div>
    </div>
    <% if (!providerHealth.healthy) { const workerReason = providerHealth.last_error?.message || (providerHealth.last_exit ? `Last exit code: ${providerHealth.last_exit.code ?? 'unknown'}` : null) || providerHealth.last_diagnostic?.message || 'No worker failure detail has been reported yet.'; %>
      <div class="callout warning"><strong>Speech recognition needs attention</strong><p><%= workerReason %> Reload the verified model below, then rerun the Companion test.</p></div>
    <% } %>
    <div class="callout info"><strong>Shared GPU awareness</strong><p>Lumi warns and benchmarks when Lumi AI already occupies GPU memory. It never unloads AI models automatically.</p></div>
  </section>

  <section class="card" aria-labelledby="devices-title">
    <div class="section-header"><div><span class="eyebrow">Access</span><h2 id="devices-title">Paired devices</h2><p class="hint">Active credentials are shown first. Switch to revoked history when needed; revoked records are permanently removed after 30 days.</p></div><span class="badge"><%= devices.length %> active</span></div>
    <div class="analysis-mode device-view-toggle" role="group" aria-label="Paired device status">
      <button class="button" type="button" data-device-view="active" aria-pressed="true">Active (<%= devices.length %>)</button>
      <button class="button subtle" type="button" data-device-view="revoked" aria-pressed="false">Revoked (<%= revokedDevices.length %>)</button>
    </div>
    <div data-active-devices>
      <% if (!devices.length) { %><div class="empty-state"><strong>No active Companion is paired</strong><p>Use Download Companion to create a package that expires after 15 minutes and works once.</p></div><% } %>
      <% if (devices.length) { %>
        <ul class="transcription-device-list">
          <% devices.forEach((device) => { %>
            <li data-device-row="<%= device.id %>"><div><strong><%= device.name %></strong><span class="hint">Last connected <%= new Date(device.last_connected_at).toLocaleString() %><% if (device.metadata?.companion_version) { %> · Companion <%= displayCompanionVersion(device.metadata.companion_version) %><% } %></span></div><div class="device-actions"><span class="badge success">Allowed</span><button class="button danger" type="button" data-revoke-device="<%= device.id %>" data-device-name="<%= device.name %>">Revoke access</button></div></li>
          <% }) %>
        </ul>
      <% } %>
    </div>
    <div data-revoked-devices hidden>
      <% if (!revokedDevices.length) { %><div class="empty-state"><strong>No revoked device history</strong><p>Revoked credentials will appear here for up to 30 days.</p></div><% } %>
      <% if (revokedDevices.length) { %>
        <ul class="transcription-device-list">
          <% revokedDevices.forEach((device) => { %><li><div><strong><%= device.name %></strong><span class="hint">Revoked <%= new Date(device.revoked_at).toLocaleString() %> · permanent removal by <%= new Date(device.revoked_at + 30 * 86400000).toLocaleDateString() %></span></div><span class="badge danger">Revoked</span></li><% }) %>
        </ul>
      <% } %>
      </div>
  </section>
</div>

<section class="card benchmark-history" aria-labelledby="benchmark-history-title" data-transcription-admin>
  <div class="section-header">
    <div><span class="eyebrow">Last hour</span><h2 id="benchmark-history-title">Transcription test analysis</h2><p class="hint">Inspect each dedicated Companion test by latency, finalized confidence, or both. Test transcripts and measurements are permanently deleted after one hour.</p></div>
    <span class="badge"><%= benchmarks.length %> retained</span>
  </div>
  <% if (!benchmarks.length) { %>
    <div class="empty-state"><strong>No dedicated tests in the last hour</strong><p>Start Accuracy &amp; latency test from the Companion Test page. Full-path checks are intentionally not retained here.</p></div>
  <% } %>
  <% benchmarks.forEach((test) => { const metricRows = [
    ['Minimum', 'min'], ['Low 1% avg', 'low_1_average'], ['Median', 'median'], ['Average', 'average'],
    ['P99', 'p99'], ['High 1% avg', 'high_1_average'], ['Maximum', 'max']
  ]; %>
    <details class="benchmark-test" data-benchmark-test data-analysis-mode="combined">
      <summary>
        <span><strong><%= new Date(test.started_at).toLocaleString() %></strong><small><%= test.source_name %> · <%= test.model_id || 'model pending' %> / <%= test.backend || 'backend pending' %> · <%= Math.round(test.duration_ms / 1000) %>s</small></span>
        <span class="badge <%= test.status === 'completed' || test.status === 'silence_timeout' ? 'success' : test.status === 'running' ? 'info' : 'warning' %>"><%= test.status.replaceAll('_', ' ') %></span>
      </summary>
      <div class="benchmark-body">
        <div class="analysis-mode" role="group" aria-label="Transcript analysis coloring">
          <button class="button subtle" type="button" data-analysis-select="latency" aria-pressed="false">Latency</button>
          <button class="button subtle" type="button" data-analysis-select="confidence" aria-pressed="false">Confidence</button>
          <button class="button" type="button" data-analysis-select="combined" aria-pressed="true">Combined</button>
        </div>
        <div class="benchmark-legends">
          <div class="benchmark-legend" aria-label="Latency color meaning"><strong>Latency</strong><span class="legend-fast">Green &lt;750 ms</span><span class="legend-good">Blue &lt;1,250 ms</span><span class="legend-trouble">Yellow &lt;2,000 ms</span><span class="legend-borderline">Orange &lt;3,000 ms</span><span class="legend-critical">Red ≥3,000 ms</span></div>
          <div class="benchmark-legend" aria-label="Confidence color meaning"><strong>Confidence</strong><span class="legend-fast">Green ≥92%</span><span class="legend-good">Blue ≥80%</span><span class="legend-trouble">Yellow ≥65%</span><span class="legend-borderline">Orange ≥45%</span><span class="legend-critical">Red &lt;45%</span></div>
        </div>
        <div class="benchmark-transcript" aria-label="Measured transcript">
          <% if (!test.words.length) { %><p class="hint"><%= test.transcript || 'No finalized words were measured.' %></p><% } %>
          <% test.words.forEach((word) => { const confidenceLabel = Number.isFinite(word.confidence) ? `${(word.confidence * 100).toFixed(1)}%` : 'not finalized'; %>
            <span class="benchmark-word" tabindex="0" data-latency="<%= word.latency_ms %>" data-confidence="<%= Number.isFinite(word.confidence) ? word.confidence : '' %>" data-tooltip="Latency <%= Math.round(word.latency_ms) %> ms · Confidence <%= confidenceLabel %> · Audio <%= Math.round(word.audio_start_ms) %>–<%= Math.round(word.audio_end_ms) %> ms"><%= word.text %></span>
          <% }) %>
        </div>
        <div class="benchmark-stat-columns">
          <% [['Latency', test.stats.latency, (value) => `${Math.round(value)} ms`], ['Final confidence', test.stats.confidence, (value) => `${(value * 100).toFixed(1)}%`]].forEach(([label, stats, format]) => { %>
            <section><h3><%= label %></h3><div class="benchmark-stat-grid">
              <% metricRows.forEach(([metricLabel, key]) => { %><div><span><%= metricLabel %></span><strong><%= Number.isFinite(stats[key]) ? format(stats[key]) : '—' %></strong></div><% }) %>
            </div><p class="hint"><%= stats.count %> measured values</p></section>
          <% }) %>
        </div>
      </div>
    </details>
  <% }) %>
</section>

<section class="card" id="speech-models" aria-labelledby="models-title" data-transcription-admin>
  <div class="section-header"><div><span class="eyebrow">Curated choices</span><h2 id="models-title">Speech models</h2><p class="hint">Downloads require confirmation and checksum verification before a model can load.</p></div></div>
  <div class="model-row">
    <% models.forEach((model) => { %>
    <article>
      <div><h3><%= model.label %></h3><p class="hint"><%= model.recommended ? 'Recommended starting point' : 'Fallback option' %> · <%= Math.round(model.bytes / 1048576) %> MiB</p></div>
      <div class="model-actions">
        <span class="badge <%= providerHealth.model === model.id && providerHealth.model_ready ? 'success' : model.status.valid ? 'info' : model.status.installed ? 'danger' : 'muted' %>"><%= providerHealth.model === model.id && providerHealth.model_ready ? 'Loaded' : providerHealth.model === model.id && model.status.valid ? 'Reload required' : model.status.valid ? 'Verified' : model.status.installed ? 'Checksum failed' : 'Not installed' %></span>
        <% if (!model.status.valid) { %><button class="button subtle" type="button" data-download-model="<%= model.id %>" data-model-label="<%= model.label %>" data-model-size="<%= Math.round(model.bytes / 1048576) %>">Download</button><% } %>
        <% if (model.status.valid && (providerHealth.model !== model.id || !providerHealth.model_ready)) { %><button class="button subtle" type="button" data-load-model="<%= model.id %>"><%= providerHealth.model === model.id ? 'Reload model' : 'Load model' %></button><% } %>
      </div>
    </article>
    <% }) %>
  </div>
  <div class="callout info"><strong>Audio privacy</strong><p>Raw audio is held only in bounded memory and is never written to disk by default. Diagnostic caption text is retained for seven days unless disabled.</p></div>
</section>
