<script lang="ts">
  import { statusStore } from '../stores/status.svelte.js'
  import { api } from '@core/api.js'
  import { esc, toast, confirmModal, badge, infoDot } from '@core/ui.js'

  const CTX_HELP = 'Kontext = das Kurzzeitgedächtnis des Modells. Größer = merkt sich mehr (längere Dateien/Chats), braucht aber mehr Speicher und wird etwas langsamer.'
  const ROLE_HELP = 'Die Rolle ist ein zusätzlicher, sprechender Name (z.B. coder). Du kannst in deinen Tools entweder den echten Modellnamen ODER die Rolle angeben — beides führt zum selben Modell.'
  const ROLES = [
    { id: 'coder', label: 'Coder', desc: 'Programmieren & Code' },
    { id: 'vision', label: 'Vision', desc: 'Bilder verstehen' },
    { id: 'scout', label: 'Scout', desc: 'Schneller Allrounder' },
    { id: 'reviewer', label: 'Reviewer', desc: 'Code/Texte prüfen' },
    { id: 'manager', label: 'Manager', desc: 'Planen & koordinieren' },
  ]

  const allModels = $derived(((statusStore.value?.models) || []) as any[])
  function refresh() { document.dispatchEvent(new Event('mc:refresh')) }

  // ---- Chat ----
  let chatModel = $state('')
  let chatMsg = $state('')
  let chatReply = $state('')
  let chatLoading = $state(false)

  const chatModels = $derived(allModels.filter((m: any) => !m.incomplete))

  async function sendChat() {
    const model = chatModel || chatModels[0]?.name
    if (!model || !chatMsg.trim()) return
    chatLoading = true; chatReply = '(wecke Modell, kann beim Laden kurz dauern…)'
    try {
      const r = await api('/api/chat', { method: 'POST', body: JSON.stringify({ model, message: chatMsg }) })
      chatReply = r.reply
    } catch (e: any) { chatReply = 'Fehler: ' + e.message }
    chatLoading = false; refresh()
  }

  const DEFAULT_TTL = 300

  // ---- Config Modal ----
  let cfgOpen = $state(false)
  let cfgModel = $state<any>(null)
  let cfgCtx = $state(8192)
  let cfgAlwaysActive = $state(false)

  function openConfig(name: string) {
    cfgModel = allModels.find((m: any) => m.name === name)
    if (!cfgModel) return
    cfgCtx = cfgModel.meta?.ctx || 8192
    cfgAlwaysActive = (cfgModel.ttl ?? DEFAULT_TTL) >= 99999
    cfgOpen = true
  }
  async function saveConfig() {
    const ttl = cfgAlwaysActive ? 99999 : DEFAULT_TTL
    try {
      await api('/api/update_model', { method: 'POST', body: JSON.stringify({ alias: cfgModel.name, ctx: cfgCtx, ttl }) })
      toast('Gespeichert — aktiv beim nächsten Modell-Start.')
      cfgOpen = false; refresh()
    } catch (e: any) { toast(e.message, true) }
  }

  // ---- Role Modal ----
  let roleOpen = $state(false)
  let roleModelName = $state('')
  let roleCustom = $state('')
  let roleCurrentRole = $state('')

  function openRole(name: string) {
    const m = allModels.find((m: any) => m.name === name)
    roleModelName = name
    roleCurrentRole = m?.role || ''
    roleCustom = ''
    roleOpen = true
  }
  async function saveRole(role: string) {
    try {
      await api('/api/set_role', { method: 'POST', body: JSON.stringify({ alias: roleModelName, role }) })
      toast(role ? `Rolle gesetzt: ${role}` : 'Rolle entfernt.')
      roleOpen = false; refresh()
    } catch (e: any) { toast(e.message, true) }
  }

  // ---- Actions ----
  async function unloadOne(name: string) {
    if (!await confirmModal({ title: `„${name}" entladen?`, body: 'Das Modell wird aus dem Grafikspeicher geworfen und lädt beim nächsten Aufruf automatisch neu.', confirmLabel: 'Entladen' })) return
    try { await api('/api/unload?model=' + encodeURIComponent(name), { method: 'POST' }); toast('Entladen: ' + name); setTimeout(refresh, 600) }
    catch (e: any) { toast(e.message, true) }
  }
  async function deleteModel(name: string) {
    if (!await confirmModal({ title: `„${name}" wirklich löschen?`, body: 'Das Modell wird aus der Konfiguration ausgetragen und seine Dateien werden von der Festplatte gelöscht, um Speicher freizugeben. <b>Das lässt sich nicht rückgängig machen</b> — später brauchst du dafür einen neuen Download.', confirmLabel: 'Endgültig löschen', danger: true })) return
    try {
      const r = await api('/api/delete_model', { method: 'POST', body: JSON.stringify({ alias: name }) })
      toast(r.note || 'Gelöscht: ' + name); setTimeout(refresh, 600)
    } catch (e: any) { toast(e.message, true) }
  }

  function capTags(caps: string[]) {
    if (!caps?.length) return '–'
    return caps.map((c: string) =>
      c === 'Code' ? '<span class="tag code">Code</span>'
      : c === 'Bild' ? '<span class="tag img">Bild</span>'
      : '<span class="tag text">Text</span>'
    ).join(' ')
  }

  function details(meta: any) {
    if (!meta) return '–'
    const q = meta.quant || '?'
    const c = meta.ctx ? Math.round(meta.ctx / 1024) + 'K' : '?'
    const s = meta.size_bytes ? (meta.size_bytes / 1024 ** 3).toFixed(1) + ' GB' : '?'
    return `<span class="mono-sm">${q} · ${c} · ${s}</span>`
  }

  function copyToClipboard(text: string) {
    navigator.clipboard?.writeText(text); toast('Kopiert: ' + text)
  }
</script>

<div id="m-head">
  <div class="pagehead">
    <div>
      <h1>Modelle</h1>
      <div class="sub">Deine konfigurierten Modelle — testen, Kontext anpassen oder aus dem Speicher werfen.</div>
    </div>
  </div>
</div>

<!-- Quick Chat -->
<div class="card">
  <div class="card-h"><h3>Schnelltest</h3></div>
  <div class="card-sub">Schreib eine Nachricht — das gewählte Modell wird automatisch geweckt.</div>
  <label>Modell</label>
  <select bind:value={chatModel}>
    {#each chatModels as m}<option value={m.name}>{m.name}</option>{/each}
  </select>
  <label>Nachricht</label>
  <textarea bind:value={chatMsg} placeholder='z.B. „Erklär mir kurz, was du kannst."'></textarea>
  <button class="primary" disabled={chatLoading} onclick={sendChat}>{chatLoading ? '…' : 'Senden'}</button>
  {#if chatReply}
    <div class="reply" style="margin-top:12px">{chatReply}</div>
  {/if}
</div>

<!-- Models Table -->
<div class="card">
  <div class="card-h"><h3>Modelle &amp; Ports</h3><span class="meta">{allModels.length ? allModels.length + ' konfiguriert' : ''}</span></div>
  <div class="card-sub">Modelle laden automatisch, sobald eine Anfrage kommt — du musst nichts manuell starten.</div>

  {#if !allModels.length}
    <div class="empty-c">
      <div class="e-t">Noch keine Modelle konfiguriert</div>
      <div class="e-s">Hol dir unter „Cookbook" ein passendes Modell.</div>
    </div>
  {:else}
    <table>
      <thead><tr><th>Modell</th><th>Kann</th><th>Details</th><th>Status</th><th>Port</th><th style="text-align:right">Aktionen</th></tr></thead>
      <tbody>
        {#each allModels as m}
          {#if m.incomplete}
            <tr style="opacity:.9">
              <td class="mid" style="font-weight:500">{m.name}<div class="li-sub mono-sm" style="color:var(--warn)">kein Modell hinterlegt</div></td>
              <td>—</td>
              <td><span class="mono-sm text-mut">leere Rolle</span></td>
              <td><span class="badge">leer</span></td>
              <td class="port">—</td>
              <td style="text-align:right;white-space:nowrap">
                <button class="ghost" onclick={() => { toast('Lade im Cookbook ein Modell und setze den Alias auf: ' + m.name); document.querySelector(".nav-item[data-view='cookbook']")?.dispatchEvent(new MouseEvent('click')) }}>Modell zuweisen</button>
                <button class="ghost del" onclick={() => deleteModel(m.name)}>Löschen</button>
              </td>
            </tr>
          {:else}
            <tr>
              <td class="mid">
                <div style="font-weight:500;display:flex;align-items:center;gap:7px;flex-wrap:wrap">
                  {m.name}
                  {#if m.role}<span class="tag" style="background:rgba(45,212,191,.14);color:var(--accent);border-color:rgba(45,212,191,.3)">{m.role}</span>{/if}
                </div>
                {#if m.meta?.filename}<div class="li-sub mono-sm">{m.meta.filename}</div>{/if}
                <div class="li-sub mono-sm" style="margin-top:3px;display:flex;align-items:center;gap:6px;flex-wrap:wrap">
                  <span class="text-mut">API-Name:</span>
                  {#each (m.api_ids?.length ? m.api_ids : [m.name]) as id}
                    <code style="cursor:pointer" title="Klicken zum Kopieren" onclick={() => copyToClipboard(id)}>{id}</code>
                  {/each}
                </div>
              </td>
              <td>{@html capTags(m.meta?.caps)}</td>
              <td>{@html details(m.meta)}</td>
              <td>{@html badge(m.state, m.download_progress)}</td>
              <td class="port">{m.port ?? 'auto'}</td>
              <td style="text-align:right;white-space:nowrap">
                <button class="ghost" onclick={() => openRole(m.name)}>Rolle</button>
                <button class="ghost" onclick={() => openConfig(m.name)}>Konfigurieren</button>
                <button class="ghost" onclick={() => unloadOne(m.name)}>Entladen</button>
                <button class="ghost del" onclick={() => deleteModel(m.name)}>Löschen</button>
              </td>
            </tr>
          {/if}
        {/each}
      </tbody>
    </table>
  {/if}
</div>

<!-- Config Modal -->
{#if cfgOpen && cfgModel}
  <div class="modal-overlay" role="dialog" onclick={e => { if ((e.target as HTMLElement).classList.contains('modal-overlay')) cfgOpen = false }}>
    <div class="modal-card">
      <button class="ghost" style="position:absolute;top:14px;right:14px" onclick={() => cfgOpen = false}>Schließen</button>
      <h3>Modell konfigurieren</h3>
      <p class="mono-sm" style="margin:-4px 0 16px">{cfgModel.name}</p>
      <label>Kontext-Größe (Tokens) {@html infoDot(CTX_HELP)}</label>
      <input type="number" bind:value={cfgCtx}>
      {#if cfgModel.meta?.optimal_ctx}
        <div class="tile" style="display:flex;justify-content:space-between;align-items:center;margin:8px 0 10px">
          <div style="flex:1">
            <div style="font-size:13px">Empfohlen für deine Hardware</div>
            <div class="hint" style="margin:4px 0 0">
              Optimal ~{Math.round(cfgModel.meta.optimal_ctx / 1024)}k → ~{cfgModel.meta.peak_ram_optimal_gb} GB Spitzenbedarf.<br>
              Aktuell ~{Math.round((cfgModel.meta.ctx || 0) / 1024)}k → ~{cfgModel.meta.peak_ram_gb} GB.
            </div>
          </div>
          <button class="ghost" onclick={() => cfgCtx = cfgModel.meta.optimal_ctx}>Optimal übernehmen</button>
        </div>
      {/if}
      <div class="hint" style="margin-bottom:14px">Es läuft immer nur <b>ein</b> Modell gleichzeitig — ein größerer Kontext hier beeinflusst deine anderen Modelle nicht.</div>

      <div class="tile" style="display:flex;justify-content:space-between;align-items:center;margin:0 0 14px">
        <div style="flex:1">
          <div style="font-size:13px;font-weight:500">Immer aktiv halten</div>
          <div class="hint" style="margin:3px 0 0">Modell bleibt dauerhaft im RAM — nie automatisch entladen. Ideal für den kleinen Scout (~5 GB), der immer schnell antworten soll.</div>
        </div>
        <label style="display:flex;align-items:center;gap:8px;margin:0;cursor:pointer;flex:0 0 auto">
          <input type="checkbox" bind:checked={cfgAlwaysActive} style="width:18px;height:18px;accent-color:var(--accent);cursor:pointer">
          <span class="mono-sm" style="color:{cfgAlwaysActive ? 'var(--accent)' : 'var(--mut)'}">
            {cfgAlwaysActive ? 'An (TTL = ∞)' : 'Aus (TTL = 5 min)'}
          </span>
        </label>
      </div>

      <button class="primary" style="width:100%;margin-top:6px" onclick={saveConfig}>Speichern</button>
    </div>
  </div>
{/if}

<!-- Role Modal -->
{#if roleOpen}
  <div class="modal-overlay" role="dialog" onclick={e => { if ((e.target as HTMLElement).classList.contains('modal-overlay')) roleOpen = false }}>
    <div class="modal-card">
      <button class="ghost" style="position:absolute;top:14px;right:14px" onclick={() => roleOpen = false}>Schließen</button>
      <h3>Rolle festlegen {@html infoDot(ROLE_HELP)}</h3>
      <p class="mono-sm" style="margin:-4px 0 16px">{roleModelName}</p>
      <div class="hint" style="margin-bottom:10px">Wähle eine Rolle als zweiten, sprechenden Namen. In deinen Tools funktionieren danach <b>beide</b>: der echte Modellname und die Rolle.</div>
      <div class="flex gap-2" style="flex-wrap:wrap;margin-bottom:12px">
        {#each ROLES as r}
          <button class="{roleCurrentRole === r.id ? 'primary' : 'ghost'}" title={r.desc} style="border-radius:999px"
            onclick={() => saveRole(r.id)}>{r.label}</button>
        {/each}
      </div>
      <label>Eigene Rolle (optional)</label>
      <input bind:value={roleCustom} placeholder="z.B. uebersetzer">
      <div class="btn-row" style="margin-top:14px;display:flex;gap:8px">
        <button class="ghost" style="flex:1" onclick={() => saveRole('')}>Rolle entfernen</button>
        <button class="primary" style="flex:2" onclick={() => saveRole(roleCustom.trim().toLowerCase())}>Speichern</button>
      </div>
    </div>
  </div>
{/if}
