import { useState, useRef, useCallback } from "react"
import { Download, Trash2, Edit3, Activity, HardDrive, X, Check, Copy } from "lucide-react"
import { api } from "@/lib/api"
import { useModels, useRouting, useConnect, useUpdates, useQueryClient, qk } from "@/lib/queries"
import { useDialog } from "@/lib/useDialog"
import { CapsChips } from "@/components/CapsChips"
import { cn } from "@/lib/utils"
import { fmtSize, fmtCtx } from "@/lib/format"
import { getBrandInfo, ROLES } from "@/components/models/ModelBadges"

export function Cockpit() {
  const qc = useQueryClient()
  const { data: modelsResp, isLoading: loading, error: loadErr } = useModels(4_000)
  const { data: routing } = useRouting(4_000)
  const { data: connectData } = useConnect()
  const { data: updates } = useUpdates(4_000)
  const { showAlert, showConfirm, showPrompt, dialogElement } = useDialog()
  const models = modelsResp?.models ?? []
  const running = modelsResp?.running ?? []
  const error = loadErr ? String(loadErr) : ""
  const reload = () => {
    qc.invalidateQueries({ queryKey: qk.models })
    qc.invalidateQueries({ queryKey: qk.routing })
  }

  // UI state
  const [activeClient, setActiveClient] = useState<"roocode" | "cursor" | "opencode" | "zed" | "continue" | null>(null)
  const [activeRoleForAssign, setActiveRoleForAssign] = useState<string | null>(null)
  const [copied, setCopied] = useState(false)
  const [hoveredNode, setHoveredNode] = useState<string | null>(null)
  const [viewMode, setViewMode] = useState<"grid" | "list">("grid")
  const [filterMode, setFilterMode] = useState<"all" | "in_use">("all")

  const filteredModels = models.filter((m) => {
    if (filterMode === "in_use") {
      return !!m.role || running.includes(m.name)
    }
    return true
  })

  // Canvas pixel tracking for pixel-perfect connection graph without non-uniform scaling
  const [dimensions, setDimensions] = useState({ width: 800, height: 360 })
  const observerRef = useRef<ResizeObserver | null>(null)

  const containerRef = useCallback((node: HTMLDivElement | null) => {
    if (observerRef.current) {
      observerRef.current.disconnect()
      observerRef.current = null
    }
    if (node) {
      const observer = new ResizeObserver((entries) => {
        if (!entries || entries.length === 0) return
        const rect = entries[0].contentRect
        setDimensions({ width: rect.width, height: rect.height })
      })
      observer.observe(node)
      observerRef.current = observer
    }
  }, [])

  const w = dimensions.width
  const h = dimensions.height

  // Helper to generate curve from client to gateway
  const getClientPath = (yPercent: number) => {
    const startX = w * 0.1
    const startY = h * yPercent
    const endX = w * 0.5
    const endY = h * 0.5
    const cp1X = w * 0.3
    const cp1Y = startY
    const cp2X = w * 0.3
    const cp2Y = endY
    return `M ${startX} ${startY} C ${cp1X} ${cp1Y}, ${cp2X} ${cp2Y}, ${endX} ${endY}`
  }

  // Helper to generate curve from gateway to role
  const getRolePath = (yPercent: number) => {
    const startX = w * 0.5
    const startY = h * 0.5
    const endX = w * 0.9
    const endY = h * yPercent
    const cp1X = w * 0.7
    const cp1Y = startY
    const cp2X = w * 0.7
    const cp2Y = endY
    return `M ${startX} ${startY} C ${cp1X} ${cp1Y}, ${cp2X} ${cp2Y}, ${endX} ${endY}`
  }

  async function handleLoadModel(name: string) {
    try {
      await api(`/api/models/${encodeURIComponent(name)}/load`, { method: "POST" })
      reload()
    } catch (e: any) {
      showAlert("Fehler", `Fehler beim Laden des Modells: ${e.message}`)
    }
  }

  async function handleUnloadModel(name: string) {
    try {
      await api(`/api/models/${encodeURIComponent(name)}/unload`, { method: "POST" })
      reload()
    } catch (e: any) {
      showAlert("Fehler", `Fehler beim Entladen des Modells: ${e.message}`)
    }
  }

  async function handleUnloadAll() {
    try {
      await api("/api/models/unload", { method: "POST" })
      reload()
    } catch (e: any) {
      showAlert("Fehler", `Fehler beim Entladen aller Modelle: ${e.message}`)
    }
  }

  async function handleRoleChange(role: string, modelName: string) {
    try {
      await api(`/api/models/${encodeURIComponent(modelName)}/role`, {
        method: "POST",
        body: JSON.stringify({ role: role || null }),
      })
      reload()
    } catch (e: any) {
      showAlert("Fehler", `Fehler beim Zuweisen der Rolle: ${e.message || e}`)
    }
  }

  async function handleSetCtx(name: string, cur: number | null) {
    showPrompt(
      "Kontextlänge anpassen",
      "Gib die gewünschte Kontextlänge in Tokens an:",
      String(cur || 32768),
      async (v) => {
        if (!v) return
        try {
          await api(`/api/models/${encodeURIComponent(name)}/ctx`, {
            method: "POST", 
            body: JSON.stringify({ ctx: parseInt(v, 10) }),
          })
          reload()
        } catch (e: any) {
          showAlert("Fehler", `Fehler beim Setzen des Kontexts: ${e.message || e}`)
        }
      }
    )
  }

  async function handleDelete(name: string) {
    showConfirm(
      "Modell löschen?",
      `Modell '${name}' und alle zugehörigen GGUF-Dateien unwiderruflich von der Box löschen?`,
      async () => {
        try {
          await api(`/api/models/${encodeURIComponent(name)}`, { method: "DELETE" })
          reload()
        } catch (e: any) {
          showAlert("Fehler", `Fehler beim Löschen: ${e.message || e}`)
        }
      }
    )
  }

  async function handleSmartUpgrade(repo: string, role: string, quant: string, toolCapable: boolean) {
    try {
      await api("/api/models/install", {
        method: "POST",
        body: JSON.stringify({ repo, role, quant, jinja: toolCapable }),
      })
      showAlert("Herunterladen gestartet", `Download für '${repo}' gestartet! Der Fortschritt wird oben angezeigt.`)
    } catch (e: any) {
      showAlert("Fehler", `Fehler beim Starten des Upgrades: ${e.message || e}`)
    }
  }

  async function copySnippet(snippet?: string) {
    if (!snippet) return
    await navigator.clipboard.writeText(snippet)
    setCopied(true)
    setTimeout(() => setCopied(false), 1500)
  }

  if (loading) return <div className="text-xs text-muted-foreground py-12 text-center">Initialisiere HUD Cockpit…</div>
  if (error) {
    return (
      <div className="rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-xs text-red-400">
        Gateway oder Engine nicht erreichbar ({error}).
      </div>
    )
  }

  // VRAM calculation: APU fallback 16GB if sysfs returns 0
  const runningWithInfo = models.filter((m) => running.includes(m.name))
  const totalRunningSize = runningWithInfo.reduce((acc, m) => acc + (m.size_bytes || 0), 0)
  const virtualMax = 16 * 1024 ** 3 // 16 GB Default
  const capacity = totalRunningSize > virtualMax ? totalRunningSize * 1.2 : virtualMax

  // Find model by role
  const getModelForRole = (role: string) => models.find((m) => m.role === role)
  const isRoleRunning = (role: string) => {
    const m = getModelForRole(role)
    return m ? running.includes(m.name) : false
  }

  return (
    <div className="space-y-8">
      {/* Styles inside Cockpit for dash flow animations */}
      <style>{`
        @keyframes flow-dash {
          to {
            stroke-dashoffset: -20;
          }
        }
        .svg-flow-path {
          stroke-dasharray: 4 6;
          animation: flow-dash 1s linear infinite;
        }
      `}</style>

      {/* ZONE A: Widescreen VRAM HUD */}
      <div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 space-y-3.5">
        <div className="flex justify-between items-center">
          <div className="flex items-center gap-2">
            <HardDrive className="h-4.5 w-4.5 text-primary" />
            <span className="text-xs font-bold uppercase tracking-wider text-foreground">VRAM / Memory Belegung</span>
          </div>
          <div className="flex items-center gap-3">
            <span className="text-[10px] font-mono text-muted-foreground">
              Llama Swap VRAM-Pool: {fmtSize(totalRunningSize)} / {fmtSize(capacity)} geladen
            </span>
            {running.length > 0 && (
              <button
                onClick={handleUnloadAll}
                className="h-6 px-2.5 rounded border border-amber-500/30 bg-amber-500/5 hover:bg-amber-500/10 text-amber-400 text-[9px] font-bold uppercase transition-all cursor-pointer"
              >
                Alle entladen
              </button>
            )}
          </div>
        </div>

        {/* The memory bar */}
        <div className="h-7 w-full rounded-xl bg-background/50 border border-border/40 overflow-hidden flex p-0.5 relative group">
          {runningWithInfo.length === 0 ? (
            <div className="w-full h-full flex items-center justify-center text-[10px] text-muted-foreground/60 italic font-mono select-none">
              VRAM Leer — Auto-Swap lädt Modelle bei Anfrage
            </div>
          ) : (
            runningWithInfo.map((m, idx) => {
              const widthPct = ((m.size_bytes || 0) / capacity) * 100
              const bgClass = [
                "from-teal-500 to-emerald-500",
                "from-indigo-500 to-blue-500",
                "from-purple-500 to-pink-500",
                "from-cyan-500 to-sky-500"
              ][idx % 4]
              return (
                <div
                  key={m.name}
                  style={{ width: `${widthPct}%` }}
                  className={cn(
                    "h-full rounded bg-gradient-to-r flex items-center justify-between px-2.5 transition-all text-white/95 shrink-0 shadow-inner select-none",
                    bgClass
                  )}
                  title={`${m.name} (${fmtSize(m.size_bytes)})`}
                >
                  <span className="text-[9px] font-bold truncate max-w-[120px] font-space tracking-wide">
                    {m.role ? `[${m.role}] ` : ""}{m.name.split("/").pop()?.replace(".gguf", "")}
                  </span>
                  <span className="text-[8px] font-mono opacity-80">{fmtSize(m.size_bytes)}</span>
                </div>
              )
            })
          )}
        </div>
      </div>

      {/* ZONE B: SVG Node Router */}
      <div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 shadow-lg shadow-black/10 space-y-4">
        <div>
          <span className="text-xs font-bold uppercase tracking-wider text-foreground">Interactive Gateway Graph</span>
          <p className="text-[10px] text-muted-foreground mt-0.5 leading-relaxed">
            Klicke links auf Editoren, um Configs zu kopieren. Klicke rechts auf Rollen, um GGUF-Zuweisungen live zu ändern.
          </p>
        </div>

        {/* The Graph Canvas Area */}
        <div ref={containerRef} className="relative w-full h-96 border border-border/30 rounded-xl bg-black/25 overflow-hidden flex">
          {/* SVG Overlay behind HTML Nodes */}
          <svg className="absolute inset-0 pointer-events-none w-full h-full">
            {/* Gradients */}
            <defs>
              <linearGradient id="cyan-to-teal" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" stopColor="#06b6d4" stopOpacity="0.45" />
                <stop offset="100%" stopColor="#0d9488" stopOpacity="0.45" />
              </linearGradient>
              <linearGradient id="active-glow" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" stopColor="#3b82f6" stopOpacity="0.8" />
                <stop offset="100%" stopColor="#10b981" stopOpacity="0.8" />
              </linearGradient>
            </defs>

            {/* Bezier Curves: Clients to Gateway (10% -> 50%) */}
            {/* Roo Code (y=10) */}
            <path d={getClientPath(0.10)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {(hoveredNode === "roocode" || activeClient === "roocode") && (
              <path d={getClientPath(0.10)} stroke="#06b6d4" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* Cursor (y=30) */}
            <path d={getClientPath(0.30)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {(hoveredNode === "cursor" || activeClient === "cursor") && (
              <path d={getClientPath(0.30)} stroke="#06b6d4" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* OpenCode (y=50) */}
            <path d={getClientPath(0.50)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {(hoveredNode === "opencode" || activeClient === "opencode") && (
              <path d={getClientPath(0.50)} stroke="#06b6d4" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* Zed (y=70) */}
            <path d={getClientPath(0.70)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {(hoveredNode === "zed" || activeClient === "zed") && (
              <path d={getClientPath(0.70)} stroke="#06b6d4" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* Continue (y=90) */}
            <path d={getClientPath(0.90)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {(hoveredNode === "continue" || activeClient === "continue") && (
              <path d={getClientPath(0.90)} stroke="#06b6d4" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* Bezier Curves: Gateway to Roles (50% -> 90%) */}
            {/* fast (y=12) */}
            <path d={getRolePath(0.12)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {isRoleRunning("fast") && (
              <path d={getRolePath(0.12)} stroke="url(#active-glow)" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* heavy (y=31) */}
            <path d={getRolePath(0.31)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {isRoleRunning("heavy") && (
              <path d={getRolePath(0.31)} stroke="url(#active-glow)" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* coder (y=50) */}
            <path d={getRolePath(0.50)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {isRoleRunning("coder") && (
              <path d={getRolePath(0.50)} stroke="url(#active-glow)" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* vision (y=69) */}
            <path d={getRolePath(0.69)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {isRoleRunning("vision") && (
              <path d={getRolePath(0.69)} stroke="url(#active-glow)" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}

            {/* scout (y=88) */}
            <path d={getRolePath(0.88)} stroke="url(#cyan-to-teal)" strokeWidth="1.5" fill="none" />
            {isRoleRunning("scout") && (
              <path d={getRolePath(0.88)} stroke="url(#active-glow)" strokeWidth="2.5" fill="none" className="svg-flow-path" />
            )}
          </svg>

          {/* HTML Nodes */}
          {/* COLUMN 1: Client nodes */}
          <div 
            className="absolute cursor-pointer select-none z-10 w-28 h-8 -translate-y-1/2 -translate-x-1/2 rounded-xl border border-border/60 bg-card/75 backdrop-blur-md flex items-center justify-center gap-1.5 px-2 hover:border-primary transition-all text-[10px] font-semibold text-foreground shadow shadow-black/20"
            style={{ left: "10%", top: "10%" }}
            onMouseEnter={() => setHoveredNode("roocode")}
            onMouseLeave={() => setHoveredNode(null)}
            onClick={() => setActiveClient(c => c === "roocode" ? null : "roocode")}
          >
            <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
            <span>Roo Code</span>
          </div>

          <div 
            className="absolute cursor-pointer select-none z-10 w-28 h-8 -translate-y-1/2 -translate-x-1/2 rounded-xl border border-border/60 bg-card/75 backdrop-blur-md flex items-center justify-center gap-1.5 px-2 hover:border-primary transition-all text-[10px] font-semibold text-foreground shadow shadow-black/20"
            style={{ left: "10%", top: "30%" }}
            onMouseEnter={() => setHoveredNode("cursor")}
            onMouseLeave={() => setHoveredNode(null)}
            onClick={() => setActiveClient(c => c === "cursor" ? null : "cursor")}
          >
            <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
            <span>Cursor IDE</span>
          </div>

          <div 
            className="absolute cursor-pointer select-none z-10 w-28 h-8 -translate-y-1/2 -translate-x-1/2 rounded-xl border border-border/60 bg-card/75 backdrop-blur-md flex items-center justify-center gap-1.5 px-2 hover:border-primary transition-all text-[10px] font-semibold text-foreground shadow shadow-black/20"
            style={{ left: "10%", top: "50%" }}
            onMouseEnter={() => setHoveredNode("opencode")}
            onMouseLeave={() => setHoveredNode(null)}
            onClick={() => setActiveClient(c => c === "opencode" ? null : "opencode")}
          >
            <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
            <span>OpenCode</span>
          </div>

          <div 
            className="absolute cursor-pointer select-none z-10 w-28 h-8 -translate-y-1/2 -translate-x-1/2 rounded-xl border border-border/60 bg-card/75 backdrop-blur-md flex items-center justify-center gap-1.5 px-2 hover:border-primary transition-all text-[10px] font-semibold text-foreground shadow shadow-black/20"
            style={{ left: "10%", top: "70%" }}
            onMouseEnter={() => setHoveredNode("zed")}
            onMouseLeave={() => setHoveredNode(null)}
            onClick={() => setActiveClient(c => c === "zed" ? null : "zed")}
          >
            <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
            <span>Zed</span>
          </div>

          <div 
            className="absolute cursor-pointer select-none z-10 w-28 h-8 -translate-y-1/2 -translate-x-1/2 rounded-xl border border-border/60 bg-card/75 backdrop-blur-md flex items-center justify-center gap-1.5 px-2 hover:border-primary transition-all text-[10px] font-semibold text-foreground shadow shadow-black/20"
            style={{ left: "10%", top: "90%" }}
            onMouseEnter={() => setHoveredNode("continue")}
            onMouseLeave={() => setHoveredNode(null)}
            onClick={() => setActiveClient(c => c === "continue" ? null : "continue")}
          >
            <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse" />
            <span>Continue</span>
          </div>

          {/* COLUMN 2: Central Gateway Node */}
          <div 
            className="absolute select-none z-10 w-36 py-3 px-4 -translate-y-1/2 -translate-x-1/2 rounded-2xl border border-primary/50 bg-card/90 backdrop-blur-md flex flex-col items-center justify-center text-center shadow-lg shadow-primary/5"
            style={{ left: "50%", top: "50%" }}
          >
            <div className="text-[10px] uppercase font-bold text-primary font-space tracking-wide">Gateway Auto</div>
            <div className="text-[10px] font-mono text-muted-foreground mt-0.5">
              Schwelle: &gt; {routing?.heavy_threshold_chars ? (routing.heavy_threshold_chars / 1000) : "4"}k Zeichen
            </div>
            <div className="mt-1 px-1.5 py-0.5 rounded bg-primary/10 border border-primary/20 text-[9px] font-semibold text-primary uppercase font-mono">
              Auto-Swap
            </div>
          </div>

          {/* COLUMN 3: Role nodes (fast, heavy, coder, vision, scout) */}
          {ROLES.map((role) => {
            const yPositions = ["12%", "31%", "50%", "69%", "88%"]
            const activeModel = getModelForRole(role)
            const isWarm = activeModel ? running.includes(activeModel.name) : false

            if (role === "agent") return null
            const indexMap = { fast: 0, heavy: 1, coder: 2, vision: 3, scout: 4 }[role] as number

            return (
              <div 
                key={role}
                className={cn(
                  "absolute z-10 w-44 py-1.5 px-3 -translate-y-1/2 -translate-x-1/2 rounded-xl border flex flex-col justify-center hover:border-primary/50 transition-all text-left shadow select-none cursor-pointer",
                  isWarm 
                    ? "border-emerald-500/50 bg-emerald-500/5 shadow-emerald-500/5" 
                    : activeModel 
                      ? "border-border/60 bg-card/75" 
                      : "border-dashed border-border/40 bg-background/20"
                )}
                style={{ left: "90%", top: yPositions[indexMap] }}
                onClick={() => setActiveRoleForAssign(role)}
              >
                <div className="flex items-center justify-between">
                  <span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">{role}</span>
                  {isWarm && <span className="h-1.5 w-1.5 rounded-full bg-emerald-400 animate-pulse" />}
                </div>
                <div className="text-[10px] font-mono font-medium truncate mt-0.5 text-foreground max-w-[150px]">
                  {activeModel ? activeModel.name.split("/").pop()?.replace(".gguf", "") : "Keine Zuweisung"}
                </div>
              </div>
            )
          })}

          {/* CLIENT SETUP MODAL WINDOW */}
          {activeClient && connectData && (
            <div className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
              <div className="w-full max-w-md rounded-2xl border border-border/80 bg-card p-6 shadow-2xl space-y-4 animate-in fade-in zoom-in-95 duration-200 flex flex-col justify-between">
                {/* Modal Header */}
                <div className="flex items-center justify-between border-b border-border/20 pb-2">
                  <span className="text-xs font-bold uppercase tracking-wider text-primary">
                    {activeClient === "roocode" && "Roo Code Setup"}
                    {activeClient === "cursor" && "Cursor Setup"}
                    {activeClient === "opencode" && "OpenCode Setup"}
                    {activeClient === "zed" && "Zed Setup"}
                    {activeClient === "continue" && "Continue Setup"}
                  </span>
                  <button 
                    onClick={() => setActiveClient(null)} 
                    className="p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer"
                  >
                    <X className="h-4 w-4" />
                  </button>
                </div>

                {/* Modal Guide Steps */}
                <div className="text-xs text-muted-foreground leading-relaxed space-y-2">
                  {activeClient === "roocode" && (
                    <ul className="list-decimal pl-4 space-y-1">
                      <li>Suche in VS Code nach der Erweiterung <strong>Roo Code</strong> und installiere sie.</li>
                      <li>Wähle in den Roo Code Einstellungen: Provider: <strong>OpenAI Compatible</strong>.</li>
                      <li>Füge das untenstehende JSON-Snippet in die <code>settings.json</code> ein.</li>
                    </ul>
                  )}
                  {activeClient === "cursor" && (
                    <ul className="list-decimal pl-4 space-y-1">
                      <li>Öffne Cursor Settings ➔ <strong>Models</strong>.</li>
                      <li>Deaktiviere Cloud-Modelle, klappe <strong>OpenAI API</strong> auf.</li>
                      <li>Trage die Base URL unten ein und aktiviere das Modell <strong>auto</strong>.</li>
                    </ul>
                  )}
                  {activeClient === "opencode" && (
                    <ul className="list-decimal pl-4 space-y-1">
                      <li>Öffne die <code>opencode.jsonc</code> Konfigurationsdatei.</li>
                      <li>Ersetze den Provider-Eintrag unter <code>provider</code> mit dem Snippet unten.</li>
                    </ul>
                  )}
                  {activeClient === "zed" && (
                    <ul className="list-decimal pl-4 space-y-1">
                      <li>Öffne die Zed Settings (<code>ctrl+,</code>).</li>
                      <li>Füge das untenstehende JSON-Segment unter <code>language_models</code> ein.</li>
                    </ul>
                  )}
                  {activeClient === "continue" && (
                    <ul className="list-decimal pl-4 space-y-1">
                      <li>Klicke auf das Zahnrad-Symbol in der Continue-Erweiterung.</li>
                      <li>Füge den Gateway-Eintrag zum <code>models</code>-Array hinzu.</li>
                    </ul>
                  )}
                </div>

                {/* Snippet box */}
                {connectData.tools && (
                  <div className="relative rounded-xl border border-border/40 bg-black/40 overflow-hidden mt-1 shrink-0">
                    <div className="flex items-center justify-between px-3 py-1.5 border-b border-border/20 bg-black/20">
                      <span className="text-[10px] font-mono text-muted-foreground">JSON Config</span>
                      <button 
                        onClick={() => copySnippet(
                          activeClient === "roocode" ? connectData.tools.cline?.snippet :
                          activeClient === "cursor" ? connectData.tools.cursor?.snippet :
                          activeClient === "opencode" ? connectData.tools.opencode?.snippet :
                          activeClient === "zed" ? connectData.tools.zed?.snippet :
                          connectData.tools.continue?.snippet
                        )}
                        className="text-xs font-semibold text-primary hover:text-primary-foreground flex items-center gap-1 cursor-pointer"
                      >
                        {copied ? <Check className="h-3.5 w-3.5 text-emerald-400" /> : <Copy className="h-3.5 w-3.5" />}
                        <span>{copied ? "Kopiert" : "Kopieren"}</span>
                      </button>
                    </div>
                    <pre className="p-3 max-h-48 overflow-y-auto text-xs font-mono text-cyan-200/90 whitespace-pre scrollbar-thin select-text">
                      <code>
                        {activeClient === "roocode" && connectData.tools.cline?.snippet}
                        {activeClient === "cursor" && connectData.tools.cursor?.snippet}
                        {activeClient === "opencode" && connectData.tools.opencode?.snippet}
                        {activeClient === "zed" && connectData.tools.zed?.snippet}
                        {activeClient === "continue" && connectData.tools.continue?.snippet}
                      </code>
                    </pre>
                  </div>
                )}
                
                <button
                  onClick={() => setActiveClient(null)}
                  className="w-full h-9 rounded-lg bg-primary text-primary-foreground hover:opacity-90 font-semibold text-xs transition-opacity cursor-pointer mt-2"
                >
                  Schließen
                </button>
              </div>
            </div>
          )}
        </div>

        {/* Legend for the connection graph */}
        <div className="flex flex-wrap items-center gap-6 mt-3 text-[10px] text-muted-foreground border-t border-border/20 pt-3">
          <span className="flex items-center gap-1.5">
            <span className="h-2 w-2 rounded-full bg-cyan-400" />
            <span>Cyan-Fluss: Client-Anfrage an Gateway</span>
          </span>
          <span className="flex items-center gap-1.5">
            <span className="h-2 w-2 rounded-full bg-emerald-500 animate-pulse" />
            <span>Grüner Puls: Aktive Verbindung / Warmes Modell geladen</span>
          </span>
          <span className="flex items-center gap-1.5">
            <span className="h-2 w-2 rounded bg-gradient-to-r from-teal-500 to-emerald-500" />
            <span>VRAM-Verlauf: Modellspezifischer Speicheranteil</span>
          </span>
        </div>
      </div>

      {/* ZONE B.5: Slot-Belegung */}
      <div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 space-y-3.5">
        <div className="text-xs font-bold uppercase tracking-wider text-muted-foreground px-1">
          Gateway Steckplatz-Belegung (Slot-Zuweisung)
        </div>
        <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
          {["fast", "heavy", "coder", "vision", "scout"].map((role) => {
            const m = models.find((x) => x.role === role)
            const isWarm = m ? running.includes(m.name) : false

            return (
              <div 
                key={role}
                onClick={() => setActiveRoleForAssign(role)}
                className={cn(
                  "rounded-xl border p-3 flex flex-col justify-between gap-2.5 transition-all cursor-pointer select-none text-left bg-background/25 hover:border-primary/45 hover:bg-background/40 group min-h-[90px]",
                  isWarm 
                    ? "border-emerald-500/40 shadow-sm shadow-emerald-500/5" 
                    : m 
                      ? "border-primary/20 bg-primary/5" 
                      : "border-border/30 border-dashed opacity-75"
                )}
              >
                <div className="flex items-center justify-between">
                  <span className={cn("text-[9px] font-bold uppercase tracking-wider font-mono px-1.5 py-0.5 rounded border",
                    role === "fast" ? "bg-cyan-500/10 text-cyan-400 border-cyan-500/20" :
                    role === "heavy" ? "bg-amber-500/10 text-amber-400 border-amber-500/20" :
                    role === "coder" ? "bg-violet-500/10 text-violet-400 border-violet-500/20" :
                    role === "vision" ? "bg-pink-500/10 text-pink-400 border-pink-500/20" :
                    "bg-teal-500/10 text-teal-400 border-teal-500/20"
                  )}>{role}</span>
                  {isWarm && <span className="h-1.5 w-1.5 rounded-full bg-emerald-400 animate-pulse" />}
                </div>
                
                <div className="text-[10px] font-mono font-medium truncate text-foreground/90 pr-1 font-space" title={m?.name}>
                  {m ? m.name.split("/").pop()?.replace(/\.gguf$/i, "") : "nicht zugewiesen"}
                </div>
                
                <div className="text-[8px] text-primary/70 group-hover:text-primary font-bold uppercase tracking-wider transition-colors font-space">
                  Ändern ➔
                </div>
              </div>
            )
          })}
        </div>
      </div>

      {/* ZONE C: Library list cards & Upgrade Radar */}
      <div className="space-y-4">
        <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 px-1">
          <div className="text-xs font-bold uppercase tracking-wider text-muted-foreground">
            Installierte Modell-Bibliothek ({filteredModels.length} von {models.length})
          </div>
          
          <div className="flex items-center gap-3">
            {/* Filter mode selector */}
            <div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
              <button
                onClick={() => setFilterMode("all")}
                className={cn(
                  "px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
                  filterMode === "all" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
                )}
              >
                Vorhanden
              </button>
              <button
                onClick={() => setFilterMode("in_use")}
                className={cn(
                  "px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
                  filterMode === "in_use" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
                )}
              >
                In Benutzung
              </button>
            </div>

            {/* Grid/List layout selector */}
            <div className="flex rounded-lg border border-border/40 bg-card/45 p-0.5">
              <button
                onClick={() => setViewMode("grid")}
                className={cn(
                  "px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
                  viewMode === "grid" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
                )}
              >
                Grid
              </button>
              <button
                onClick={() => setViewMode("list")}
                className={cn(
                  "px-2.5 py-1 rounded-md text-[9px] font-bold uppercase transition-all cursor-pointer",
                  viewMode === "list" ? "bg-primary text-primary-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
                )}
              >
                List
              </button>
            </div>
          </div>
        </div>
        
        {viewMode === "grid" ? (
          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {filteredModels.length === 0 ? (
              <div className="col-span-full text-xs text-muted-foreground border border-dashed border-border/60 rounded-2xl p-12 text-center select-none">
                {filterMode === "in_use" 
                  ? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)." 
                  : "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."}
              </div>
            ) : (
              filteredModels.map((m) => {
                const isRunning = running.includes(m.name)
                const hasUpgrade = updates?.model_list.find((u) => u.role === m.role)
                const brand = getBrandInfo(m.name)

                return (
                  <div 
                    key={m.name} 
                    className={cn(
                      "rounded-2xl border bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 flex flex-col justify-between gap-4 transition-all duration-300 hover:border-primary/40 group relative overflow-hidden",
                      isRunning 
                        ? "border-primary/45 shadow-primary/5" 
                        : m.role 
                          ? "border-primary/30 bg-primary/5 shadow-inner" 
                          : "border-border/60"
                    )}
                  >
                    <div className="space-y-3">
                      <div className="flex items-start justify-between gap-3">
                        <div className="flex gap-2.5 min-w-0">
                          {/* Brand Icon Badge */}
                          <div className={cn("w-7 h-7 rounded-lg border flex items-center justify-center font-bold text-xs shrink-0 shadow-sm", brand.color)} title={brand.name}>
                            {brand.initial}
                          </div>

                          <div className="min-w-0">
                            <h3 className="text-xs font-bold tracking-tight text-foreground line-clamp-2 break-all font-mono" title={m.name}>
                              {m.name.split("/").pop()}
                            </h3>
                            <div className="flex items-center gap-2 flex-wrap mt-1">
                              <span className="text-[9px] font-mono text-muted-foreground bg-background/40 px-1.5 py-0.5 rounded border border-border/30">
                                {m.quant || "GGUF"}
                              </span>
                              {isRunning && (
                                <span className="flex items-center gap-1 text-[9px] font-semibold text-emerald-400 uppercase tracking-wider">
                                  <Activity className="h-3 w-3 animate-pulse" /> Warm
                                </span>
                              )}
                              {m.role && (
                                <span className="px-1.5 py-0.5 rounded bg-primary/10 border border-primary/20 text-[9px] font-mono text-primary font-bold uppercase">
                                  {m.role}
                                </span>
                              )}
                              {m.prompt_cache && (
                                <span className="px-1.5 py-0.5 rounded bg-cyan-500/10 border border-cyan-500/20 text-[9px] font-mono text-cyan-400 font-bold uppercase" title="Prompt Caching aktiv">
                                  PC
                                </span>
                              )}
                              {m.spec_draft_model && (
                                <span className="px-1.5 py-0.5 rounded bg-emerald-500/10 border border-emerald-500/20 text-[9px] font-mono text-emerald-400 font-bold uppercase" title={`Speculative Decoding aktiv (Draft: ${m.spec_draft_model})`}>
                                  SPEC
                                </span>
                              )}
                              {m.parallel_slots > 1 && (
                                <span className="px-1.5 py-0.5 rounded bg-violet-500/10 border border-violet-500/20 text-[9px] font-mono text-violet-400 font-bold uppercase" title={`${m.parallel_slots} parallele Slots aktiv`}>
                                  SLOTS: {m.parallel_slots}
                                </span>
                              )}
                              {m.incomplete && (
                                <span className="px-1.5 py-0.5 rounded bg-amber-500/10 border border-amber-500/20 text-[9px] font-mono text-amber-400 font-bold uppercase" title="GGUF-Datei fehlt — Modell kann nicht geladen werden">
                                  ⚠ Datei fehlt
                                </span>
                              )}
                            </div>
                          </div>
                        </div>
                      </div>

                      <div className="border-t border-border/30 pt-3 flex flex-wrap gap-1">
                        <CapsChips caps={m.capabilities} />
                      </div>
                    </div>

                    <div className="space-y-3 pt-1">
                      <div className="grid grid-cols-2 gap-2 text-[10px] font-mono text-muted-foreground">
                        <div className="flex items-center gap-1.5 p-2 bg-background/20 rounded-lg border border-border/20">
                          <HardDrive className="h-3.5 w-3.5 text-primary/80" />
                          <div>
                            <div className="text-[8px] uppercase tracking-wider font-semibold text-muted-foreground/60">Größe</div>
                            <div className="text-foreground font-semibold">{fmtSize(m.size_bytes)}</div>
                          </div>
                        </div>

                        <div className="flex items-center gap-1.5 p-2 bg-background/20 rounded-lg border border-border/20">
                          <Edit3 className="h-3.5 w-3.5 text-primary/80" />
                          <div>
                            <div className="text-[8px] uppercase tracking-wider font-semibold text-muted-foreground/60">Kontext</div>
                            <div className="text-foreground font-semibold">{fmtCtx(m.ctx)}</div>
                          </div>
                        </div>
                      </div>

                      {/* Smart Upgrade radar trigger banner */}
                      {hasUpgrade && (
                        <div className="p-3 bg-amber-500/5 border border-amber-500/30 rounded-xl space-y-2 flex flex-col justify-between shrink-0">
                          <div className="text-[9px] font-semibold text-amber-400 flex items-center gap-1">
                            <span className="w-1.5 h-1.5 rounded-full bg-amber-400 animate-ping" />
                            <span>Upgrade verfügbar: {hasUpgrade.repo.split("/").pop()}</span>
                          </div>
                          <button
                            onClick={() => handleSmartUpgrade(hasUpgrade.repo, m.role!, m.quant || "Q4_K_M", m.capabilities.tools !== "no")}
                            className="h-7 w-full flex items-center justify-center gap-1 rounded-lg bg-amber-500 text-black text-[10px] font-bold hover:bg-amber-400 transition-colors cursor-pointer"
                          >
                            <Download className="h-3 w-3" /> Smart-Swap starten
                          </button>
                        </div>
                      )}

                      {/* Actions row at the bottom of Grid Card */}
                      <div className="flex items-center gap-1.5 border-t border-border/20 pt-3 mt-auto">
                        <button
                          onClick={() => isRunning ? handleUnloadModel(m.name) : handleLoadModel(m.name)}
                          disabled={m.incomplete && !isRunning}
                          className={cn(
                            "flex-1 h-7 rounded-lg text-[9px] font-bold uppercase transition-all border flex items-center justify-center gap-1",
                            m.incomplete && !isRunning
                              ? "border-border/30 bg-background/10 text-muted-foreground/50 cursor-not-allowed"
                              : isRunning
                                ? "border-amber-500/30 bg-amber-500/5 hover:bg-amber-500/15 text-amber-400 cursor-pointer"
                                : "border-primary/30 bg-primary/5 hover:bg-primary/15 text-primary cursor-pointer"
                          )}
                        >
                          {isRunning ? "Entladen" : "Laden"}
                        </button>
                        <button
                          onClick={() => handleSetCtx(m.name, m.ctx)}
                          className="h-7 px-2.5 rounded-lg border border-border/40 text-[9px] font-bold uppercase hover:bg-accent text-muted-foreground transition-colors cursor-pointer"
                          title="Kontextlänge anpassen"
                        >
                          Ctx
                        </button>
                        <button
                          onClick={() => handleDelete(m.name)}
                          className="h-7 w-7 rounded-lg border border-border/40 text-muted-foreground hover:text-red-400 hover:bg-red-500/5 flex items-center justify-center transition-colors cursor-pointer"
                          title="Modell löschen"
                        >
                          <Trash2 className="h-3.5 w-3.5" />
                        </button>
                      </div>
                    </div>
                  </div>
                )
              })
            )}
          </div>
        ) : (
          <div className="space-y-2">
            {filteredModels.length === 0 ? (
              <div className="text-xs text-muted-foreground border border-dashed border-border/60 rounded-2xl p-12 text-center select-none">
                {filterMode === "in_use" 
                  ? "Keine Modelle in Benutzung (keine Zuweisung oder warm geladene Modelle)." 
                  : "Keine Modelle konfiguriert. Verwende den Tab \"Modelle finden\" zum Herunterladen."}
              </div>
            ) : (
              filteredModels.map((m) => {
                const isRunning = running.includes(m.name)
                const brand = getBrandInfo(m.name)

                return (
                  <div 
                    key={m.name} 
                    className={cn(
                      "rounded-xl border bg-card/45 backdrop-blur-md p-3.5 shadow-lg shadow-black/5 flex flex-col sm:flex-row sm:items-center justify-between gap-3 hover:border-primary/40 transition-all",
                      isRunning 
                        ? "border-primary/45" 
                        : m.role 
                          ? "border-primary/30 bg-primary/5" 
                          : "border-border/60"
                    )}
                  >
                    <div className="flex items-center gap-3 min-w-0">
                      {/* Brand Icon */}
                      <div className={cn("w-8 h-8 rounded-lg border border-border/40 flex items-center justify-center font-bold text-xs shrink-0 shadow-sm", brand.color)} title={brand.name}>
                        {brand.initial}
                      </div>
                      
                      <div className="min-w-0 text-left">
                        <div className="flex items-center gap-2 flex-wrap">
                          <h4 className="text-xs font-bold text-foreground truncate max-w-[250px] sm:max-w-[400px] break-all font-mono" title={m.name}>
                            {m.name.split("/").pop()}
                          </h4>
                          {m.role && (
                            <span className="px-1.5 py-0.5 rounded bg-primary/10 border border-primary/20 text-[8px] font-mono text-primary font-bold uppercase shrink-0">
                              {m.role}
                            </span>
                          )}
                          {m.prompt_cache && (
                            <span className="px-1.5 py-0.5 rounded bg-cyan-500/10 border border-cyan-500/20 text-[8px] font-mono text-cyan-400 font-bold uppercase shrink-0" title="Prompt Caching aktiv">
                              PC
                            </span>
                          )}
                          {m.spec_draft_model && (
                            <span className="px-1.5 py-0.5 rounded bg-emerald-500/10 border border-emerald-500/20 text-[8px] font-mono text-emerald-400 font-bold uppercase shrink-0" title={`Speculative Decoding aktiv (Draft: ${m.spec_draft_model})`}>
                              SPEC
                            </span>
                          )}
                          {m.parallel_slots > 1 && (
                            <span className="px-1.5 py-0.5 rounded bg-violet-500/10 border border-violet-500/20 text-[8px] font-mono text-violet-400 font-bold uppercase shrink-0" title={`${m.parallel_slots} parallele Slots aktiv`}>
                              SLOTS: {m.parallel_slots}
                            </span>
                          )}
                          {m.incomplete && (
                            <span className="px-1.5 py-0.5 rounded bg-amber-500/10 border border-amber-500/20 text-[8px] font-mono text-amber-400 font-bold uppercase shrink-0" title="GGUF-Datei fehlt">
                              ⚠ Datei fehlt
                            </span>
                          )}
                          {isRunning && (
                            <span className="flex items-center gap-0.5 text-[8px] font-semibold text-emerald-400 uppercase tracking-wider shrink-0">
                              <span className="h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse" /> warm
                            </span>
                          )}
                        </div>
                        <div className="text-[10px] text-muted-foreground/80 flex items-center gap-2 mt-0.5">
                          <span>Größe: {fmtSize(m.size_bytes)}</span>
                          <span>•</span>
                          <span>Kontext: {fmtCtx(m.ctx)}</span>
                          <span>•</span>
                          <span className="font-mono text-[9px]">{m.quant || "GGUF"}</span>
                        </div>
                      </div>
                    </div>
                    
                    {/* Chips and Actions */}
                    <div className="flex items-center gap-3 shrink-0 self-end sm:self-auto">
                      <div className="hidden lg:flex flex-wrap gap-1">
                        <CapsChips caps={m.capabilities} />
                      </div>
                      
                      <div className="flex items-center gap-1.5">
                        <button
                          onClick={() => isRunning ? handleUnloadModel(m.name) : handleLoadModel(m.name)}
                          disabled={m.incomplete && !isRunning}
                          className={cn(
                            "h-7 px-3 rounded-lg text-[9px] font-bold uppercase transition-all border flex items-center gap-1",
                            m.incomplete && !isRunning
                              ? "border-border/30 bg-background/10 text-muted-foreground/50 cursor-not-allowed"
                              : isRunning
                                ? "border-amber-500/30 bg-amber-500/5 hover:bg-amber-500/15 text-amber-400 cursor-pointer"
                                : "border-primary/30 bg-primary/5 hover:bg-primary/15 text-primary cursor-pointer"
                          )}
                        >
                          {isRunning ? "Entladen" : "Laden"}
                        </button>
                        <button 
                          onClick={() => handleSetCtx(m.name, m.ctx)}
                          className="h-7 px-2.5 rounded-lg border border-border/40 text-[9px] font-bold uppercase hover:bg-accent text-muted-foreground transition-all cursor-pointer"
                          title="Kontextlänge anpassen"
                        >
                          Ctx
                        </button>
                        <button 
                          onClick={() => handleDelete(m.name)} 
                          className="h-7 w-7 rounded-lg flex items-center justify-center border border-border/40 text-muted-foreground hover:text-red-400 hover:bg-red-500/5 transition-all cursor-pointer"
                          title="Modell löschen"
                        >
                          <Trash2 className="h-3.5 w-3.5" />
                        </button>
                      </div>
                    </div>
                  </div>
                )
              })
            )}
          </div>
        )}
      </div>

      {/* Role Assignment Modal */}
      {activeRoleForAssign && (
        <div className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
          <div className="w-full max-w-md rounded-2xl border border-border/80 bg-card p-6 shadow-2xl space-y-4 animate-in fade-in zoom-in-95 duration-200">
            <div className="flex items-center justify-between border-b border-border/20 pb-2">
              <h3 className="text-xs font-bold uppercase tracking-wider text-primary">
                Rolle '{activeRoleForAssign}' konfigurieren
              </h3>
              <button 
                onClick={() => setActiveRoleForAssign(null)}
                className="p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer"
              >
                <X className="h-4 w-4" />
              </button>
            </div>
            <p className="text-xs text-muted-foreground">
              Wähle ein Modell aus deiner Bibliothek für die Rolle <strong className="text-foreground">{activeRoleForAssign}</strong>:
            </p>
            
            <div className="space-y-1.5 max-h-60 overflow-y-auto pr-1">
              <button 
                onClick={() => {
                  handleRoleChange(activeRoleForAssign, "")
                  setActiveRoleForAssign(null)
                }}
                className="w-full text-left px-3 py-2 rounded-lg text-xs hover:bg-accent text-red-400 font-semibold cursor-pointer border border-red-500/20 bg-red-500/5 flex items-center justify-between"
              >
                <span>Zuweisung entfernen</span>
              </button>
              {models.map((m) => (
                <button
                  key={m.name}
                  onClick={() => {
                    handleRoleChange(activeRoleForAssign, m.name)
                    setActiveRoleForAssign(null)
                  }}
                  className={cn(
                    "w-full text-left px-3 py-2.5 rounded-lg text-xs hover:bg-accent flex items-center justify-between font-mono cursor-pointer border border-border/30",
                    m.role === activeRoleForAssign 
                      ? "text-primary font-bold bg-primary/10 border-primary/30" 
                      : "text-foreground bg-background/20"
                  )}
                >
                  <div className="flex flex-col text-left">
                    <span className="truncate max-w-[280px] font-semibold">{m.name.split("/").pop()?.replace(".gguf", "")}</span>
                    <span className="text-[9px] text-muted-foreground mt-0.5">{fmtSize(m.size_bytes)} · {m.quant}</span>
                  </div>
                  {m.role === activeRoleForAssign && <Check className="h-4 w-4 shrink-0 text-primary" />}
                </button>
              ))}
            </div>
          </div>
        </div>
      )}

      {dialogElement}
    </div>
  )
}
