<script lang="ts">
  import { api } from '@core/api.js'
  import { toast } from '@core/ui.js'

  // ---- Typen ----
  type MsgRole = 'user' | 'hermes' | 'info' | 'tool' | 'error'
  type Msg = { role: MsgRole; content: string; tool?: string; args?: any }

  // ---- State ----
  let messages   = $state<Msg[]>([])
  let input      = $state('')
  let thinking   = $state(false)
  let voiceOn    = $state(false)
  let recording  = $state(false)
  let status     = $state<any>(null)
  let setupOpen  = $state(false)
  let pubkey     = $state('')
  let ws         = $state<WebSocket | null>(null)
  let currentBot = $state('')   // aktuell gestreamter Hermes-Token

  // ---- WebSocket ----
  function connect() {
    const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'
    const token = localStorage.getItem('mc_token') || ''
    const u = `${proto}//${location.host}/api/hermes/chat${token ? '?token=' + token : ''}`
    const sock = new WebSocket(u)

    sock.onmessage = (e) => {
      const m = JSON.parse(e.data)
      if (m.type === 'thinking') {
        thinking = true
      } else if (m.type === 'info') {
        // kleine Info-Meldung (Modell-Anzeige)
      } else if (m.type === 'token') {
        thinking = false
        currentBot += m.content
        // letzter Eintrag aktualisieren oder neu anlegen
        const last = messages[messages.length - 1]
        if (last?.role === 'hermes') {
          messages = [...messages.slice(0, -1), { role: 'hermes', content: currentBot }]
        } else {
          messages = [...messages, { role: 'hermes', content: currentBot }]
        }
      } else if (m.type === 'tool_call') {
        thinking = false
        const args = m.args || {}
        const preview = Object.values(args).join(' ').slice(0, 60)
        messages = [...messages, { role: 'tool', content: preview, tool: m.name }]
      } else if (m.type === 'tool_result') {
        // Tool-Result in letzten Tool-Eintrag schreiben
        const last = messages.findLast(x => x.role === 'tool' && x.tool === m.name)
        if (last) last.content = m.content
        messages = [...messages]
      } else if (m.type === 'error') {
        thinking = false
        messages = [...messages, { role: 'error', content: m.content }]
      } else if (m.type === 'done') {
        thinking = false
        currentBot = ''
        if (voiceOn) speakLast()
      }
    }

    sock.onclose = () => {
      ws = null
      setTimeout(connect, 3000)
    }
    sock.onerror = () => sock.close()
    ws = sock
  }

  // ---- Senden ----
  async function send() {
    const text = input.trim()
    if (!text || !ws || ws.readyState !== 1) return
    messages = [...messages, { role: 'user', content: text }]
    input = ''
    currentBot = ''
    ws.send(JSON.stringify({ message: text }))
  }

  // ---- Voice: Aufnahme ----
  let mediaRecorder: MediaRecorder | null = null
  let audioChunks: Blob[] = []

  async function startRecording() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      audioChunks = []
      mediaRecorder = new MediaRecorder(stream)
      mediaRecorder.ondataavailable = (e) => audioChunks.push(e.data)
      mediaRecorder.onstop = () => {
        stream.getTracks().forEach(t => t.stop())
        sendAudio()
      }
      mediaRecorder.start()
      recording = true
    } catch (e: any) {
      toast('Mikrofon-Zugriff verweigert: ' + e.message, true)
    }
  }

  function stopRecording() {
    mediaRecorder?.stop()
    recording = false
  }

  async function sendAudio() {
    const blob = new Blob(audioChunks, { type: 'audio/webm' })
    const form = new FormData()
    form.append('audio', blob, 'voice.webm')
    try {
      const r = await fetch('/api/hermes/transcribe', {
        method: 'POST',
        headers: localStorage.getItem('mc_token')
          ? { 'X-MC-Token': localStorage.getItem('mc_token')! }
          : {},
        body: form,
      })
      const data = await r.json()
      if (data.text) {
        input = data.text
        send()
      } else {
        toast('Konnte Audio nicht verstehen.', true)
      }
    } catch (e: any) {
      toast('Transkription fehlgeschlagen: ' + e.message, true)
    }
  }

  // ---- Voice: Ausgabe ----
  async function speakLast() {
    const last = [...messages].reverse().find(m => m.role === 'hermes')
    if (!last) return
    try {
      const r = await fetch('/api/hermes/tts', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...(localStorage.getItem('mc_token') ? { 'X-MC-Token': localStorage.getItem('mc_token')! } : {})
        },
        body: JSON.stringify({ text: last.content }),
      })
      if (!r.ok) return
      const blob = await r.blob()
      const url  = URL.createObjectURL(blob)
      const audio = new Audio(url)
      audio.onended = () => URL.revokeObjectURL(url)
      audio.play()
    } catch { /* TTS optional */ }
  }

  // ---- Status laden ----
  async function loadStatus() {
    try { status = await api('/api/hermes/status') }
    catch { status = null }
  }

  async function loadPubkey() {
    try {
      const r = await api('/api/hermes/pubkey')
      pubkey = r.pubkey
    } catch { pubkey = '' }
  }

  // ---- Hilfsfunktionen ----
  function toolLabel(name: string) {
    const map: Record<string, string> = {
      read_file: '📄 Lese Datei',
      list_directory: '📁 Liste Verzeichnis',
      run_command: '⚡ Befehl',
      get_system_status: '📊 System-Status',
      get_memories: '🧠 Gedächtnis',
      add_memory: '💾 Speichern',
      web_search: '🌐 Websuche',
    }
    return map[name] || name
  }

  function copyKey() {
    navigator.clipboard?.writeText(pubkey)
    toast('SSH-Key kopiert')
  }

  // ---- Boot ----
  $effect(() => {
    connect()
    loadStatus()
  })
</script>

<!-- ==================== HEADER ==================== -->
<div class="pagehead" style="display:flex;justify-content:space-between;align-items:flex-start">
  <div>
    <h1>Hermes</h1>
    <div class="sub">Dein lokaler KI-Assistent — kennt den Bosgame, lernt mit.</div>
  </div>
  <div class="flex gap-2" style="flex-shrink:0;margin-top:6px;flex-wrap:wrap;align-items:center">
    <!-- Whisper-Status -->
    <span class="chip" style="font-size:11px;{status?.whisper === 'ready' || status?.whisper === 'installed'
      ? 'color:var(--accent);border-color:var(--accent)'
      : 'color:var(--mut)'}">
      🎙 Whisper: {status?.whisper ?? '…'}
    </span>
    <!-- SSH-Status -->
    <span class="chip" style="font-size:11px;{status?.ssh_ok
      ? 'color:var(--accent);border-color:var(--accent)'
      : 'color:var(--mut)'}">
      🔑 SSH: {status?.ssh_ok ? 'verbunden' : status?.ssh_configured ? 'Fehler' : 'nicht eingerichtet'}
    </span>
    <!-- Voice Toggle -->
    <button class="ghost" style="padding:4px 12px;font-size:12px;{voiceOn ? 'border-color:var(--accent);color:var(--accent)' : ''}"
      onclick={() => voiceOn = !voiceOn}>
      🔊 Voice {voiceOn ? 'an' : 'aus'}
    </button>
    <!-- Setup -->
    <button class="ghost" style="padding:4px 10px;font-size:12px"
      onclick={() => { setupOpen = !setupOpen; if (setupOpen) { loadStatus(); loadPubkey() } }}>
      ⚙ Setup
    </button>
  </div>
</div>

<!-- ==================== SETUP-WIZARD ==================== -->
{#if setupOpen}
  <div class="card" style="border-color:rgba(45,212,191,.3)">
    <div class="card-h"><h3>Hermes Setup-Wizard</h3></div>

    <!-- Whisper -->
    <div class="tile" style="margin-bottom:10px">
      <div style="display:flex;justify-content:space-between;align-items:center">
        <div>
          <b>Whisper (Sprache → Text)</b>
          <div class="card-sub" style="font-size:12px">faster-whisper muss auf dem Bosgame installiert sein</div>
        </div>
        <span class="chip" style="font-size:11px;{status?.whisper !== 'not_installed' ? 'color:#7ee29a' : 'color:#ff9b95'}">
          {status?.whisper !== 'not_installed' ? '✓ OK' : '✗ fehlt'}
        </span>
      </div>
      {#if status?.whisper === 'not_installed'}
        <div class="log" style="margin-top:8px"><code>pip install faster-whisper</code></div>
      {/if}
    </div>

    <!-- Piper -->
    <div class="tile" style="margin-bottom:10px">
      <div style="display:flex;justify-content:space-between;align-items:center">
        <div>
          <b>Piper TTS (Text → Sprache)</b>
          <div class="card-sub" style="font-size:12px">Piper-Binary + deutsche Stimme</div>
        </div>
        <span class="chip" style="font-size:11px;{status?.piper === 'ready' ? 'color:#7ee29a' : 'color:#ff9b95'}">
          {status?.piper === 'ready' ? '✓ OK' : '✗ fehlt'}
        </span>
      </div>
      {#if status?.piper !== 'ready'}
        <div class="log" style="margin-top:8px"><code>{"# Auf dem Bosgame:\nmkdir -p /opt/mission-control/piper/voices\n# Piper Binary + Thorsten-Stimme (Anleitung in Guides)"}</code></div>
      {/if}
    </div>

    <!-- Windows SSH -->
    <div class="tile">
      <div style="display:flex;justify-content:space-between;align-items:center">
        <div>
          <b>Windows SSH-Verbindung</b>
          <div class="card-sub" style="font-size:12px">Damit Hermes Dateien auf deinem Windows-PC ändern kann</div>
        </div>
        <span class="chip" style="font-size:11px;{status?.ssh_ok ? 'color:#7ee29a' : 'color:var(--mut)'}">
          {status?.ssh_ok ? '✓ verbunden' : 'optional'}
        </span>
      </div>

      {#if !status?.ssh_ok}
        <div style="margin-top:12px">
          <div style="font-size:12.5px;font-weight:500;margin-bottom:8px">Einrichtung (einmalig, ~3 Minuten):</div>

          <div style="margin-bottom:8px">
            <div class="card-sub" style="font-size:11.5px;margin-bottom:4px">1. PowerShell als Admin — OpenSSH Server installieren:</div>
            <div class="log"><code>Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0</code></div>
          </div>

          <div style="margin-bottom:8px">
            <div class="card-sub" style="font-size:11.5px;margin-bottom:4px">2. Dienst starten und dauerhaft aktivieren:</div>
            <div class="log"><code>{"Start-Service sshd\nSet-Service -Name sshd -StartupType Automatic"}</code></div>
          </div>

          <div style="margin-bottom:8px">
            <div class="card-sub" style="font-size:11.5px;margin-bottom:4px">3. SSH-Ordner erstellen:</div>
            <div class="log"><code>{"New-Item -ItemType Directory -Force -Path \"$env:USERPROFILE\\.ssh\""}</code></div>
          </div>

          {#if pubkey}
            <div style="margin-bottom:8px">
              <div class="card-sub" style="font-size:11.5px;margin-bottom:4px">4. Bosgame-Key eintragen (in Windows PowerShell):</div>
              <div style="position:relative">
                <button class="ghost" style="position:absolute;top:6px;right:6px;font-size:11px;padding:2px 8px;z-index:1"
                  onclick={copyKey}>Kopieren</button>
                <div class="log"><code>{"echo \"" + pubkey + "\" >> \"$env:USERPROFILE\\.ssh\\authorized_keys\""}</code></div>
              </div>
            </div>
          {:else}
            <div class="card-sub" style="font-size:11.5px">SSH-Key nicht gefunden — bitte auf dem Bosgame generieren:
              <code style="display:block;margin-top:4px">ssh-keygen -t ed25519 -C "hermes-agent@bosgame" -f ~/.ssh/id_ed25519_hermes_agent -N ""</code>
            </div>
          {/if}

          <div style="margin-bottom:8px">
            <div class="card-sub" style="font-size:11.5px;margin-bottom:4px">5. Windows-IP in Mission Control Env-Var setzen:</div>
            <div class="log"><code>HERMES_WINDOWS_HOST=192.168.178.XXX</code></div>
          </div>

          <button class="primary" style="margin-top:4px" onclick={() => { loadStatus(); toast('Status aktualisiert') }}>
            Verbindung testen
          </button>
        </div>
      {/if}
    </div>
  </div>
{/if}

<!-- ==================== CHAT ==================== -->
<div class="card" style="padding:0;display:flex;flex-direction:column;min-height:420px">

  <!-- Nachrichten-Liste -->
  <div style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px"
       id="hermes-msgs">
    {#if messages.length === 0}
      <div class="empty-c" style="margin:auto">
        <div class="e-t">Hermes ist bereit</div>
        <div class="e-s">Stelle eine Frage oder gib einen Auftrag — per Text oder Sprache.</div>
        <div style="margin-top:16px;display:flex;flex-direction:column;gap:6px">
          {#each [
            'Was läuft gerade auf dem System?',
            'Zeig mir den Inhalt von /etc/llama-swap/config.yaml',
            'Suche nach den neuesten Qwen3-Modellen',
          ] as suggestion}
            <button class="ghost" style="font-size:12.5px;text-align:left"
              onclick={() => { input = suggestion; send() }}>
              {suggestion}
            </button>
          {/each}
        </div>
      </div>
    {/if}

    {#each messages as msg (msg)}
      {#if msg.role === 'user'}
        <div style="display:flex;justify-content:flex-end">
          <div style="background:rgba(45,212,191,.15);border:1px solid rgba(45,212,191,.3);
                      border-radius:12px 12px 2px 12px;padding:10px 14px;max-width:75%;
                      font-size:13.5px;line-height:1.5;word-break:break-word">
            {msg.content}
          </div>
        </div>

      {:else if msg.role === 'hermes'}
        <div style="display:flex;gap:8px;align-items:flex-start">
          <div style="width:28px;height:28px;border-radius:50%;background:rgba(45,212,191,.2);
                      border:1px solid rgba(45,212,191,.4);display:flex;align-items:center;
                      justify-content:center;font-size:14px;flex-shrink:0">H</div>
          <div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);
                      border-radius:2px 12px 12px 12px;padding:10px 14px;max-width:80%;
                      font-size:13.5px;line-height:1.6;word-break:break-word;white-space:pre-wrap">
            {msg.content}
          </div>
        </div>

      {:else if msg.role === 'tool'}
        <div style="display:flex;align-items:center;gap:8px;color:var(--mut);font-size:11.5px;
                    padding:4px 8px;background:rgba(255,255,255,.02);border-radius:6px">
          <span>{toolLabel(msg.tool || '')}</span>
          {#if msg.content}
            <span style="font-family:monospace;font-size:11px;opacity:.7;overflow:hidden;
                          text-overflow:ellipsis;white-space:nowrap;max-width:400px">
              {msg.content}
            </span>
          {/if}
        </div>

      {:else if msg.role === 'info'}
        <div style="text-align:center;color:var(--mut);font-size:11px">{msg.content}</div>

      {:else if msg.role === 'error'}
        <div style="background:rgba(240,87,63,.1);border:1px solid rgba(240,87,63,.3);
                    border-radius:8px;padding:8px 12px;color:#ff9b95;font-size:12.5px">
          ⚠ {msg.content}
        </div>
      {/if}
    {/each}

    {#if thinking}
      <div style="display:flex;gap:8px;align-items:center;color:var(--mut);font-size:12px">
        <div style="width:28px;height:28px;border-radius:50%;background:rgba(45,212,191,.1);
                    border:1px solid rgba(45,212,191,.2);display:flex;align-items:center;
                    justify-content:center;font-size:14px">H</div>
        <span style="animation:pulse 1.2s ease-in-out infinite">denkt nach…</span>
      </div>
    {/if}
  </div>

  <!-- Input-Bereich -->
  <div style="border-top:1px solid rgba(255,255,255,.07);padding:12px 16px;display:flex;gap:8px;align-items:flex-end">
    <textarea
      rows="2"
      placeholder="Frage stellen oder Aufgabe beschreiben…"
      style="flex:1;resize:none;font-size:13.5px;line-height:1.5;min-height:44px;max-height:160px"
      bind:value={input}
      onkeydown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send() } }}
    ></textarea>

    <!-- Mikrofon-Button -->
    <button
      class="ghost"
      style="padding:10px 12px;flex-shrink:0;font-size:18px;line-height:1;
             {recording ? 'border-color:var(--err);color:var(--err)' : ''}"
      title={recording ? 'Aufnahme stoppen' : 'Spracheingabe'}
      onmousedown={startRecording}
      onmouseup={stopRecording}
      ontouchstart={startRecording}
      ontouchend={stopRecording}>
      {recording ? '⏹' : '🎤'}
    </button>

    <!-- Senden-Button -->
    <button
      class="primary"
      style="padding:10px 18px;flex-shrink:0"
      disabled={!input.trim() || !ws || ws.readyState !== 1}
      onclick={send}>
      Senden
    </button>
  </div>
</div>

<style>
  @keyframes pulse {
    0%, 100% { opacity: 1 }
    50%       { opacity: .4 }
  }
</style>
