<script lang="ts">
  import { jobsStore } from '../stores/jobs.svelte.js'
  import { systemStore } from '../stores/system.svelte.js'
  import { api } from '@core/api.js'
  import { toast, fmtBytes } from '@core/ui.js'

  const jobs = $derived(jobsStore.value)
  const tracked = $derived(jobsStore.tracked)
  const sys = $derived(systemStore.value)

  const MAX_HIST = 60
  let hist = $state({ cpu: [] as number[], ram: [] as number[], gpu: [] as number[] })

  $effect(() => {
    if (!sys) return
    const g = sys.gpu
    const gpuPct = g && (g.vram.total + g.gtt.total) > 0
      ? ((g.vram.used + g.gtt.used) / (g.vram.total + g.gtt.total)) * 100 : 0
    hist.cpu = [...hist.cpu, sys.cpu?.percent ?? 0].slice(-MAX_HIST)
    hist.ram = [...hist.ram, sys.ram.percent].slice(-MAX_HIST)
    hist.gpu = [...hist.gpu, gpuPct].slice(-MAX_HIST)
  })

  const gpuPct = $derived(() => {
    const g = sys?.gpu
    if (g && (g.vram.total + g.gtt.total) > 0)
      return ((g.vram.used + g.gtt.used) / (g.vram.total + g.gtt.total)) * 100
    return 0
  })

  const finishedCount = $derived(jobs.filter(j => j.state !== 'running' && j.state !== 'queued').length)
  const failedCount = $derived(jobs.filter(j => j.state === 'failed').length)

  function jobPct(j: any) {
    if (j.state !== 'running') return null
    if (typeof j.progress === 'number') return Math.min(100, j.progress)
    const last = (j.log || []).at(-1) || ''
    const m = last.match(/(\d+(?:\.\d+)?)\s*%/)
    return m ? Math.min(100, parseFloat(m[1])) : null
  }

  function fmtEta(s: number | null) {
    if (s == null || s < 0) return ''
    return s >= 90 ? `noch ~${Math.round(s / 60)} min` : `noch ~${Math.max(1, Math.round(s))} s`
  }

  function statusBadge(s: string) {
    if (s === 'done') return '<span class="badge b-run">fertig</span>'
    if (s === 'failed') return '<span class="badge b-err">fehler</span>'
    if (s === 'canceled') return '<span class="badge">abgebrochen</span>'
    return '<span class="badge b-load">läuft…</span>'
  }

  function dotClass(s: string) {
    return s === 'done' ? 'on' : (s === 'failed' || s === 'canceled') ? '' : 'load'
  }

  async function cancelJob(id: string) {
    try { await api(`/api/jobs/${id}/cancel`, { method: 'POST' }); toast('Abbruch angefordert…') }
    catch (e: any) { toast(e.message, true) }
  }

  async function deleteJob(id: string) {
    try { await api(`/api/jobs/${id}`, { method: 'DELETE' }) }
    catch (e: any) { toast(e.message, true) }
  }

  async function clearJobs() {
    try {
      const r = await api('/api/jobs/clear', { method: 'POST' })
      toast(`${r.removed} Einträge entfernt.`)
    } catch (e: any) { toast(e.message, true) }
  }

  function sparkBars(arr: number[], cssVar: string) {
    return arr.map(v =>
      `<div style="width:4px;background:var(${cssVar});opacity:.55;height:${Math.max(2, v)}%;border-radius:2px"></div>`
    ).join('')
  }
</script>

<div class="pagehead">
  <div>
    <h1>Aktivität</h1>
    <div class="sub">Live-Auslastung und laufende Aufgaben (Downloads, Updates) mit Protokoll.</div>
  </div>
</div>

<!-- System KPI Tiles -->
{#if sys}
  {@const gpu = gpuPct()}
  <div class="tiles">
    <div class="tile">
      <div class="t-l">Prozessor (CPU)</div>
      <div class="t-v">{Math.round(sys.cpu?.percent ?? 0)}<small> %</small></div>
      <div class="t-s">{sys.cpu?.temp != null ? `${Math.round(sys.cpu.temp)}° CPU-Temp` : 'Auslastung'}</div>
    </div>
    <div class="tile">
      <div class="t-l">Arbeitsspeicher</div>
      <div class="t-v">{Math.round(sys.ram.percent)}<small> %</small></div>
      <div class="t-s">{fmtBytes(sys.ram.used)} / {fmtBytes(sys.ram.total)}</div>
    </div>
    <div class="tile">
      <div class="t-l">Grafikspeicher</div>
      <div class="t-v">{Math.round(gpu)}<small> %</small></div>
      <div class="t-s">{sys.gpu_temp != null ? `${Math.round(sys.gpu_temp)}° GPU-Temp` : 'VRAM + GTT'}</div>
    </div>
  </div>

  <!-- System Metrics Card -->
  <div class="card">
    <div class="card-h"><h3>System-Metriken (Bosgame)</h3></div>
    <div class="card-sub">Live-Auslastung deines Mini-PCs, alle 0,5 Sekunden.</div>
    <div class="kv" style="margin-bottom:6px">
      <div class="kv-row"><span class="kv-k">Arbeitsspeicher (RAM)</span><span class="kv-v">{fmtBytes(sys.ram.used)} / {fmtBytes(sys.ram.total)}</span></div>
      <div class="kv-row"><span class="kv-k">Grafikspeicher (VRAM + GTT)</span>
        <span class="kv-v">{sys.gpu ? `${fmtBytes(sys.gpu.vram.used + sys.gpu.gtt.used)} / ${fmtBytes(sys.gpu.vram.total + sys.gpu.gtt.total)}` : '–'}</span>
      </div>
      <div class="kv-row"><span class="kv-k">Speicherplatz (Disk)</span><span class="kv-v">{Math.round(sys.disk?.percent ?? 0)} % belegt</span></div>
      <div class="kv-row"><span class="kv-k">Temperatur (GPU / CPU)</span>
        <span class="kv-v">{sys.gpu_temp != null ? Math.round(sys.gpu_temp) + '°' : '–'} / {sys.cpu?.temp != null ? Math.round(sys.cpu.temp) + '°' : '–'}</span>
      </div>
    </div>
    <div class="grid grid-3" style="margin-top:14px">
      <div><div class="meta text-xs">CPU-Verlauf</div><div style="display:flex;align-items:flex-end;gap:2px;height:38px;margin-top:10px">{@html sparkBars(hist.cpu, '--accent')}</div></div>
      <div><div class="meta text-xs">RAM-Verlauf</div><div style="display:flex;align-items:flex-end;gap:2px;height:38px;margin-top:10px">{@html sparkBars(hist.ram, '--purple')}</div></div>
      <div><div class="meta text-xs">VRAM-Verlauf</div><div style="display:flex;align-items:flex-end;gap:2px;height:38px;margin-top:10px">{@html sparkBars(hist.gpu, '--on')}</div></div>
    </div>
  </div>
{/if}

<!-- Jobs Card -->
<div class="card">
  <div class="card-h">
    <h3>Hintergrund-Aufgaben</h3>
    <span class="meta">{jobs.length ? (failedCount ? failedCount + ' Fehler' : jobs.length + ' gesamt') : ''}</span>
    {#if finishedCount}
      <button class="ghost" style="margin-left:auto;padding:4px 11px;font-size:12px" onclick={clearJobs}>Verlauf leeren</button>
    {/if}
  </div>
  <div class="card-sub">Downloads &amp; Updates erscheinen hier mit Live-Protokoll — zum Aufklappen klicken.</div>

  {#if !jobs.length}
    <div class="empty-c">
      <div class="e-t">Gerade nichts los.</div>
      <div class="e-s">Alles ruhig — keine laufenden Aufgaben.</div>
    </div>
  {:else}
    {#each jobs as j}
      {@const p = jobPct(j)}
      {@const eta = j.state === 'running' ? fmtEta(j.eta_s) : ''}
      {@const rate = j.state === 'running' && j.rate_bps ? fmtBytes(j.rate_bps) + '/s' : ''}
      {@const extra = [eta, rate].filter(Boolean).join(' · ')}
      {@const open = tracked.includes(j.id)}
      <div class="job">
        <div class="job-h" role="button" tabindex="0"
          onclick={() => jobsStore.toggle(j.id)}
          onkeydown={e => e.key === 'Enter' && jobsStore.toggle(j.id)}>
          <span class="li-dot {dotClass(j.state)}"></span>
          <span class="mid">{j.label}</span>
          {#if p != null}
            <span class="mono-sm" style="margin-left:auto">{Math.round(p)} %{extra ? ` · ${extra}` : ''}</span>
          {/if}
          {#if j.state === 'running'}
            <button class="ghost" style="{p == null ? 'margin-left:auto;' : ''}margin-right:2px;padding:2px 9px;font-size:12px"
              onclick={e => { e.stopPropagation(); cancelJob(j.id) }}>Abbrechen</button>
          {:else}
            <button class="ghost" title="Aus Verlauf entfernen" style="margin-left:auto;margin-right:2px;padding:2px 9px;font-size:14px;line-height:1"
              onclick={e => { e.stopPropagation(); deleteJob(j.id) }}>×</button>
          {/if}
          {@html statusBadge(j.state)}
        </div>
        {#if p != null && j.state === 'running'}
          <div class="bar" style="margin-top:8px"><i style="width:{p}%"></i></div>
        {/if}
        {#if open}
          <div class="log">{(j.log || []).join('\n')}</div>
        {/if}
      </div>
    {/each}
  {/if}
</div>
