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

  const s = $derived(statusStore.value)
  const allModels = $derived(((s?.models || []) as any[]).filter((m: any) => !m.incomplete))

  const url = $derived(baseUrl())
  let selectedTool = $state('zed')
  let selectedModelIds = $state<string[]>([])
  let testResult = $state('')
  let testOk = $state(false)

  function baseUrl() { return `http://${location.hostname}:8080/v1` }
  function isLanIp(h: string) { return /^\d{1,3}(\.\d{1,3}){3}$/.test(h) }
  function behindProxy() { return location.protocol === 'https:' || !isLanIp(location.hostname) }

  const activeIds = $derived(
    selectedModelIds.length ? selectedModelIds : allModels.map((m: any) => m.name)
  )
  const firstModel = $derived(activeIds[0] || 'coder')
  const visionModel = $derived(allModels.find((m: any) => m.meta?.caps?.includes('Bild'))?.name)

  function zedBlock(url: string, ids: string[]) {
    const ms = ids.length ? allModels.filter((m: any) => ids.includes(m.name)) : (allModels.length ? allModels : [{ name: 'coder', meta: {} }])
    const entries = ms.map((m: any) => {
      const img = (m.meta?.caps || []).some((c: string) => /Bild|Vision/i.test(c))
      const ctx = m.meta?.ctx || 131072  // nutze konfigurierten Kontext des Modells (Standard: 128k)
      return `          { "name": "${m.name}", "display_name": "${m.name}", "max_tokens": ${ctx}${img ? `, "capabilities": { "tools": true, "images": true }` : ''} }`
    }).join(',\n')
    return `"language_models": {\n  "openai_compatible": {\n    "bosgame": {\n      "api_url": "${url}",\n      "available_models": [\n${entries}\n      ]\n    }\n  }\n}`
  }

  function openCodeBlock(url: string, ids: string[]) {
    // Modell-Objekte mit Meta (für ctx) statt nur IDs
    const ms = ids.length
      ? allModels.filter((m: any) => ids.includes(m.name))
      : (allModels.length ? allModels : [{ name: 'coder', meta: {} }])
    const modelMap = ms.map((m: any) => {
      const ctx = m.meta?.ctx || 131072  // konfigurierten Kontext übergeben (Standard: 128k)
      return `      "${m.name}": { "name": "${m.name}", "contextWindowSize": ${ctx} }`
    }).join(',\n')
    return `"provider": {\n  "llama-swap": {\n    "npm": "@ai-sdk/openai-compatible",\n    "name": "Bosgame (llama-swap)",\n    "options": {\n      "baseURL": "${url}",\n      "apiKey": "local"\n    },\n    "models": {\n${modelMap}\n    }\n  }\n}`
  }

  async function testConnection() {
    testResult = 'Teste…'
    try {
      const r = await api('/api/integration/test')
      testOk = r.ok
      testResult = r.ok
        ? `✓ Verbunden — ${r.models.length} Modell(e): ${r.models.join(', ')}`
        : `✗ Keine Verbindung: ${r.error}`
    } catch (e: any) { testOk = false; testResult = '✗ ' + e.message }
  }

  function copyCode(el: HTMLElement) {
    const code = el.querySelector('code')
    if (code) navigator.clipboard?.writeText(code.textContent || '')
  }
  function copyVal(inp: HTMLInputElement) {
    navigator.clipboard?.writeText(inp.value)
  }
</script>

<div class="pagehead">
  <div>
    <h1>Verbinden</h1>
    <div class="sub">Schritt für Schritt: KI-Modelle in deine Tools einbinden — getestet, erklärt, mit Copy-Paste-Config.</div>
  </div>
</div>

<!-- Step 1: Connection -->
<div class="card">
  <div class="card-h"><h3>1 · Verbindung prüfen</h3></div>
  <div class="card-sub">Stelle sicher, dass die LLM-Engine erreichbar ist, bevor du Tools konfigurierst.</div>
  <label>Engine-Adresse (für alle Tools)</label>
  <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px">
    <input class="mono-sm" readonly value={url} style="flex:1;margin:0">
    <button class="ghost" onclick={e => { const inp = (e.currentTarget as HTMLElement).previousElementSibling as HTMLInputElement; copyVal(inp) }}>Kopieren</button>
  </div>
  {#if behindProxy()}
    <div class="alert warn" style="margin:0 0 12px">
      <span class="a-dot"></span>
      <span>Du öffnest Mission Control über einen <b>Proxy/Namen</b>. Die Engine läuft auf <b>Port 8080 ohne HTTPS</b> direkt am Bosgame.
      Trag in deinen Tools die <b>LAN-IP</b> ein: <code>http://192.168.178.151:8080/v1</code> — nicht den Proxy-Namen.</span>
    </div>
  {/if}
  <div class="btn-row" style="display:flex;align-items:center;gap:10px">
    <button class="primary" onclick={testConnection}>Verbindung testen</button>
    {#if testResult}
      <span class="mono-sm" style="color:{testOk ? '#7ee29a' : '#ff9b95'}">{testResult}</span>
    {/if}
  </div>
</div>

<!-- Auto-Swap explanation -->
<div class="card">
  <div class="card-h"><h3>Wie funktioniert das Auto-Swap?</h3></div>
  <div style="display:flex;flex-direction:column;gap:10px">
    {#each [
      ['⚡', 'Kein manuelles Starten nötig', 'Wenn du in Zed oder OpenCode „coder" auswählst und eine Anfrage sendest, lädt llama-swap das Modell automatisch — in ca. 2–5 Sekunden.'],
      ['🔄', 'Modelle wechseln sich automatisch ab', 'Rufst du ein anderes Modell auf, entlädt llama-swap das aktuelle (nach TTL-Ablauf) und lädt das neue. Es läuft immer nur eines gleichzeitig.'],
      ['🧠', 'Zwei Modelle gleichzeitig aktiv halten', 'Du hast 124 GB RAM — genug für z.B. Scout 8B (~5 GB) dauerhaft geladen + ein größeres Modell das swappt. Dafür beim Scout im Modelle-Tab → Konfigurieren die TTL auf 99999 setzen.']
    ] as [emoji, title, desc]}
      <div class="tile" style="display:flex;gap:12px;align-items:flex-start">
        <span style="font-size:20px;line-height:1;flex:0 0 auto">{emoji}</span>
        <div>
          <div style="font-weight:500;font-size:13.5px">{title}</div>
          <div class="card-sub" style="margin:4px 0 0">{desc}</div>
        </div>
      </div>
    {/each}
  </div>
</div>

<!-- Step 2: Model selector -->
{#if allModels.length}
  <div class="card">
    <div class="card-h">
      <h3>2 · Modelle auswählen</h3>
      <span class="meta">{selectedModelIds.length ? `${selectedModelIds.length} von ${allModels.length} ausgewählt` : 'alle werden eingeschlossen'}</span>
    </div>
    <div class="card-sub">Wähle, welche Modelle im Config-Snippet erscheinen sollen.</div>
    <div class="flex gap-2" style="flex-wrap:wrap">
      {#each allModels as m}
        {@const active = selectedModelIds.includes(m.name)}
        <span class="chip" style="cursor:pointer;{active ? 'background:rgba(45,212,191,.2);border-color:var(--accent);color:var(--accent)' : ''}"
          role="button" tabindex="0"
          onclick={() => selectedModelIds = active ? selectedModelIds.filter(x => x !== m.name) : [...selectedModelIds, m.name]}
          onkeydown={e => e.key === 'Enter' && (selectedModelIds = active ? selectedModelIds.filter(x => x !== m.name) : [...selectedModelIds, m.name])}>
          {m.name}
        </span>
      {/each}
    </div>
    {#if selectedModelIds.length}
      <div style="margin-top:10px">
        <a href="#" onclick={e => { e.preventDefault(); selectedModelIds = [] }} style="color:var(--mut);font-size:12.5px">Auswahl aufheben (alle)</a>
      </div>
    {/if}
  </div>
{/if}

<!-- Step 3: Tool picker -->
<div class="card">
  <div class="card-h"><h3>3 · Tool wählen</h3></div>
  <div class="card-sub">Für welches Werkzeug brauchst du die Konfiguration?</div>
  <div class="grid grid-4" style="gap:8px">
    {#each [
      ['zed', 'Zed', 'Schneller nativer Editor — Empfohlen'],
      ['opencode', 'OpenCode', 'Open-Source Coding-Agent (Terminal/Desktop)'],
      ['cline', 'Cline / Cursor', 'VS Code Extension, Bring-Your-Own-Key'],
      ['openwebui', 'OpenWebUI', 'Browser-Chat-Interface']
    ] as [id, label, desc]}
      <button class="card-btn{selectedTool === id ? ' cb-best' : ''}" style="text-align:left;padding:12px 16px" onclick={() => selectedTool = id}>
        <div style="font-weight:500;font-size:13.5px">{label}</div>
        <div class="card-sub" style="margin:3px 0 0">{desc}</div>
      </button>
    {/each}
  </div>
</div>

<!-- Step 4: Config snippet -->
<div class="card">
  <div class="card-h"><h3>4 · Config-Snippet</h3></div>
  {#if selectedTool === 'zed'}
    {@const block = zedBlock(url, activeIds)}
    <p>Öffne die Zed-Settings mit <code>Cmd/Strg + ,</code> und <b>füge diesen Block</b> in deine bestehende <code>settings.json</code> ein. Falls bereits ein <code>"bosgame"</code>-Eintrag existiert: vorher löschen.</p>
    <div class="alert warn" style="margin-bottom:12px;padding:10px 14px"><span class="a-dot"></span><span>Nur diesen Block einfügen, <b>nicht die ganze Datei ersetzen</b> — sonst gehen andere Einstellungen verloren.</span></div>
    <div style="position:relative">
      <button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1" onclick={e => copyCode(e.currentTarget!.parentElement!)}>Kopieren</button>
      <div class="log" style="max-height:none"><code>{block}</code></div>
    </div>
    <p style="margin-top:12px"><b>API-Key:</b> Öffne den Agent-Panel → Anbieter <b>bosgame</b> → trag irgendeinen Wert ein (z.B. <code>local</code>).</p>
    <div class="hint">Danach im Agent-Panel das Modell <b>bosgame / {firstModel}</b> auswählen.</div>
  {:else if selectedTool === 'opencode'}
    {@const block = openCodeBlock(url, activeIds)}
    <p>Datei anlegen oder öffnen:</p>
    <p class="mono-sm" style="line-height:1.6">Windows: <code>%USERPROFILE%\.config\opencode\opencode.json</code></p>
    <div class="alert warn" style="margin:8px 0 12px;padding:10px 14px"><span class="a-dot"></span><span>Nur den <code>"provider"</code>-Block einfügen. Falls bereits ein <code>"llama-swap"</code>-Eintrag vorhanden: <b>vorher löschen</b>, sonst erscheinen Modelle doppelt.</span></div>
    <div style="position:relative">
      <button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1" onclick={e => copyCode(e.currentTarget!.parentElement!)}>Kopieren</button>
      <div class="log" style="max-height:none"><code>{block}</code></div>
    </div>
    <p style="margin-top:12px">Danach in OpenCode <code>/models</code> → <b>llama-swap/{firstModel}</b> wählen.</p>
  {:else if selectedTool === 'cline'}
    <p>In Cline/Cursor den Provider <b>„OpenAI Compatible"</b> wählen:</p>
    <label>Basis-URL</label>
    <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px">
      <input class="mono-sm" readonly value={url} style="flex:1;margin:0">
      <button class="ghost" onclick={e => copyVal((e.currentTarget as HTMLElement).previousElementSibling as HTMLInputElement)}>Kopieren</button>
    </div>
    <label>Modell-ID</label>
    <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px">
      <input class="mono-sm" readonly value={firstModel} style="flex:1;margin:0">
      <button class="ghost" onclick={e => copyVal((e.currentTarget as HTMLElement).previousElementSibling as HTMLInputElement)}>Kopieren</button>
    </div>
    <div class="hint">API-Key: ein beliebiger Wert (z.B. <code>local</code>).</div>
  {:else if selectedTool === 'openwebui'}
    <p>Settings → Admin Panel → Connections → neue OpenAI-Verbindung:</p>
    <label>Basis-URL</label>
    <div class="flex gap-2" style="align-items:stretch;margin-bottom:12px">
      <input class="mono-sm" readonly value={url} style="flex:1;margin:0">
      <button class="ghost" onclick={e => copyVal((e.currentTarget as HTMLElement).previousElementSibling as HTMLInputElement)}>Kopieren</button>
    </div>
    <label>API-Key</label>
    <div class="flex gap-2" style="align-items:stretch">
      <input class="mono-sm" readonly value="dummy-key" style="flex:1;margin:0">
      <button class="ghost" onclick={e => copyVal((e.currentTarget as HTMLElement).previousElementSibling as HTMLInputElement)}>Kopieren</button>
    </div>
  {/if}
</div>

<!-- Vision -->
{#if visionModel}
  {@const snippet = `curl ${url}/chat/completions \\\n  -H "Content-Type: application/json" \\\n  -d '{\n  "model": "${visionModel}",\n  "messages": [{"role":"user","content":[{"type":"text","text":"Was ist auf dem Bild falsch?"},{"type":"image_url","image_url":{"url":"data:image/png;base64,<DEIN_BILD>"}}]}]\n}'`}
  <div class="card">
    <div class="card-h">
      <h3>Bilder einbinden (Vision)</h3>
      <span class="chip" style="background:rgba(63,185,80,.12);border-color:rgba(63,185,80,.25);color:#7ee29a">{@html icon('check')} „{visionModel}" bereit</span>
    </div>
    <div class="card-sub">Mit Vision-Modellen kannst du Screenshots oder Fehlerbilder direkt mitschicken.</div>
    <div style="position:relative;margin-top:8px">
      <button class="ghost" style="position:absolute;top:8px;right:8px;z-index:1" onclick={e => copyCode(e.currentTarget!.parentElement!)}>Kopieren</button>
      <div class="log" style="max-height:none"><code>{snippet}</code></div>
    </div>
  </div>
{/if}
