import { mount } from 'svelte'
import { api, getToken, setToken, getHfToken, setHfToken } from '@core/api.js'
import { initNav } from '@core/nav.js'
import { ICON } from '@core/ui.js'
import { statusStore } from './stores/status.svelte.js'
import { jobsStore } from './stores/jobs.svelte.js'
import { systemStore } from './stores/system.svelte.js'

// Svelte panels — vollständig migriert
import OverviewPanel from './panels/OverviewPanel.svelte'
import ModelsPanel from './panels/ModelsPanel.svelte'
import JobsPanel from './panels/JobsPanel.svelte'
import ServerPanel from './panels/ServerPanel.svelte'
import CookbookPanel from './panels/CookbookPanel.svelte'
import ConnectPanel from './panels/ConnectPanel.svelte'
import NewsPanel from './panels/NewsPanel.svelte'
import GuidesPanel from './panels/GuidesPanel.svelte'
import MemoryPanel from './panels/MemoryPanel.svelte'
import HermesPanel from './panels/HermesPanel.svelte'

let prevModelStates: Record<string, string> = {}

function flashSwap() {
  const el = document.getElementById('top-active-text')
  if (el) { el.classList.add('swap-flash'); setTimeout(() => el.classList.remove('swap-flash'), 900) }
}

function applyStatus(s: any) {
  const dot = document.getElementById('swdot')
  const label = document.getElementById('swlabel')
  const activeText = document.getElementById('top-active-text')

  if (!s) {
    dot && (dot.className = 'dot off')
    label && (label.textContent = 'Backend nicht erreichbar')
    activeText && (activeText.textContent = 'Backend offline')
    showAlert('Backend nicht erreichbar – läuft uvicorn?', false)
  } else {
    const host = (s.swap_url || '').replace(/^https?:\/\//, '')
    dot && (dot.className = 'dot ' + (s.swap_ok ? 'on' : 'off'))
    label && (label.textContent = (s.swap_ok ? 'LLM-Engine: Online – ' : 'LLM-Engine: Offline – ') + host)
    const LOADED = ['running', 'ready', 'loading', 'starting']
    const active = (s.models || []).find((m: any) => LOADED.includes(m.state))
    if (activeText) {
      if (active) {
        const ctx = active.meta?.ctx ? ` <span style="color:var(--mut);font-size:11.5px">· ${Math.round(active.meta.ctx / 1024)}k ctx</span>` : ''
        const stateLabel = active.state === 'loading' || active.state === 'starting' ? ' <span style="color:var(--warn);font-size:11.5px">lädt…</span>' : ''
        activeText.innerHTML = `<b style="color:var(--accent)">${active.name}</b>${ctx}${stateLabel}`
      } else {
        activeText.innerHTML = '<span style="color:var(--mut)">Kein Modell im VRAM</span>'
      }
    }
    if (s.swap_ok) hideAlert()
    else showAlert(`LLM-Engine nicht erreichbar unter <b>${host}</b> – läuft der llama-swap Dienst?`, true)

    const newStates: Record<string, string> = {}
    for (const m of (s.models || [])) newStates[m.name] = m.state
    for (const [name, state] of Object.entries(newStates)) {
      const prev = prevModelStates[name]
      if (prev && prev !== state && (state === 'running' || state === 'loading')) { flashSwap(); break }
    }
    prevModelStates = newStates
  }
  setSecChip(s)
  statusStore.set(s)
}

function setSecChip(s: any) {
  const chip = document.getElementById('sec-chip')
  const tx = document.getElementById('sec-chip-tx')
  if (!chip || !tx) return
  chip.classList.toggle('ok', !!s?.secured)
  tx.textContent = s?.secured ? 'Geschützt · Heimnetz' : 'Nur im Heimnetz (offen)'
}

function applyJobs(jobs: any[]) {
  jobsStore.set(jobs || [])
}

function applySystem(sys: any) {
  systemStore.set(sys)
}

function showAlert(html: string, warn: boolean) {
  const a = document.getElementById('alert')!
  a.className = 'alert' + (warn ? ' warn' : '')
  a.innerHTML = `<span class="a-dot"></span><span>${html}</span>`
  a.style.display = 'flex'
}
function hideAlert() {
  const a = document.getElementById('alert')
  if (a) a.style.display = 'none'
}

// Update badges
const goView = (v: string) => (document.querySelector(`.nav-item[data-view="${v}"]`) as HTMLElement)?.click()

function mkBadge(text: string, cls: string, view: string, title?: string) {
  const s = document.createElement('span')
  s.className = 'upd-badge' + (cls ? ' ' + cls : '')
  s.textContent = text
  if (title) s.title = title
  s.onclick = () => goView(view)
  return s
}

async function pollUpdates() {
  try {
    const u = await api('/api/updates')
    const el = document.getElementById('update-badges'); if (!el) return
    const age = u.apt_cache_age_h as number | null
    const stale = age != null && age > 24
    const ageNote = age != null ? ` · apt-Cache: vor ${age}h` : ''
    el.innerHTML = ''
    el.appendChild(mkBadge(
      u.os > 0 ? `OS: ${u.os} Updates` : stale ? 'OS: ?' : 'OS: aktuell',
      u.os > 0 ? 'warn' : stale ? 'warn' : 'ok', 'server',
      u.os > 0 ? `${u.os} Pakete${ageNote}` : stale ? `apt-Cache veraltet (${age}h)` : `Keine Updates${ageNote}`
    ))
    el.appendChild(mkBadge(u.engine > 0 ? 'Engine: Update' : 'Engine: aktuell', u.engine > 0 ? 'warn' : 'ok', 'server'))
    el.appendChild(mkBadge(u.models > 0 ? `Modelle: ${u.models}` : 'Modelle: aktuell', u.models > 0 ? 'warn' : 'ok', 'news'))
  } catch { /* noop */ }
}

async function pollStatus() {
  try { applyStatus(await api('/api/status')) }
  catch { applyStatus(null) }
}
async function pollJobs() {
  try { applyJobs(await api('/api/jobs')) }
  catch { /* noop */ }
}

function connectSystemStream() {
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
  const ws = new WebSocket(`${protocol}//${window.location.host}/api/system/stream`)
  ws.onmessage = e => { try { applySystem(JSON.parse(e.data)) } catch {} }
  ws.onclose = () => { setTimeout(connectSystemStream, 3000) }
  ws.onerror = () => ws.close()
}

// ---- Boot ----

// Icons in Nav/Logo injizieren
document.getElementById('logo')?.innerHTML !== undefined &&
  (document.getElementById('logo')!.innerHTML = ICON.logo)
document.querySelectorAll('[data-ic]').forEach(n => {
  (n as HTMLElement).innerHTML = ICON[(n as HTMLElement).dataset.ic || ''] || ''
})

// Svelte panels mounten
const panels: [string, any][] = [
  ['overview', OverviewPanel],
  ['models', ModelsPanel],
  ['activity', JobsPanel],
  ['server', ServerPanel],
  ['cookbook', CookbookPanel],
  ['connect', ConnectPanel],
  ['news', NewsPanel],
  ['guides', GuidesPanel],
  ['memory', MemoryPanel],
  ['hermes', HermesPanel],
]
for (const [view, Panel] of panels) {
  const el = document.querySelector(`.view[data-view="${view}"]`)
  if (el) mount(Panel, { target: el })
}

initNav('overview')

// Token / Settings
const tokenInput = document.getElementById('token') as HTMLInputElement | null
if (tokenInput) {
  tokenInput.value = getToken()
  tokenInput.addEventListener('change', e => { setToken((e.target as HTMLInputElement).value); pollStatus() })
}
const hfInput = document.getElementById('hf-token') as HTMLInputElement | null
if (hfInput) {
  hfInput.value = getHfToken()
  hfInput.addEventListener('change', e => setHfToken((e.target as HTMLInputElement).value))
}
const sbtn = document.getElementById('nav-settings')
const smod = document.getElementById('settings-modal')
const scls = document.getElementById('sm-close')
if (sbtn && smod && scls) {
  sbtn.addEventListener('click', () => (smod!.style.display = 'flex'))
  scls.addEventListener('click', () => (smod!.style.display = 'none'))
}

function tickClock() {
  const c = document.getElementById('clock')
  if (c) c.textContent = new Date().toTimeString().slice(0, 5)
}

document.addEventListener('mc:refresh', pollStatus as EventListener)
pollStatus(); pollJobs(); connectSystemStream()
setInterval(tickClock, 1000)
setInterval(pollStatus, 3000)
setInterval(pollJobs, 1500)
pollUpdates()
setInterval(pollUpdates, 60000)
