import { useState } from "react"
import { Download, Trash2, Edit3, Activity, HardDrive, Check, Zap, Bot } from "lucide-react"
import { api, setGroup, type ModelInfo, type RoleRecResp } from "@/lib/api"
import { useModels, useGroups, useUpdates, useHermesBrain, useSystemStatus, 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, RoleLabel, roleMeta } from "@/components/models/ModelBadges"
import { SpecDraftModal } from "@/components/models/SpecDraftModal"
import { RoleAssignModal } from "./cockpit/RoleAssignModal"
import { LaneEditor } from "@/components/models/LaneEditor"
import { WarmSetManager } from "@/components/models/WarmSetManager"
import { useExpertMode } from "@/lib/useExpertMode"

export function Cockpit() {
  const qc = useQueryClient()
  const { data: modelsResp, isLoading: loading, error: loadErr } = useModels(4_000)
  const { data: updates } = useUpdates(4_000)
  const { data: brain } = useHermesBrain()
  const { data: sysStatus } = useSystemStatus()
  const { data: groupsResp } = useGroups()
  const { showAlert, showConfirm, showPrompt, dialogElement } = useDialog()
  const expert = useExpertMode()
  // Schutzgeländer: Modelle in einer lebenswichtigen Rolle (Hirn/Gedächtnis) dürfen
  // nicht gelöscht/entladen werden. Das `protected`-Flag kommt zentral aus roleMeta.
  const isProtected = (role?: string | null) => !!roleMeta(role).protected
  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 })
  }

  // Ko-Residenz-Gruppe „brains": ihre Mitglieder dürfen gleichzeitig resident bleiben
  // (Hirn + Augen verdrängen sich nicht). Ein Modell außerhalb der Gruppe lädt exklusiv.
  const brainsGroup = groupsResp?.groups?.brains
  const brainsMembers = brainsGroup?.members ?? []
  const isCoresident = (name: string) => brainsMembers.includes(name)
  // Ist gerade ein warmes Hirn-Mitglied resident, das ein gruppenloses Lade-Modell verdrängen würde?
  const brainsWarm = brainsMembers.some((mname) => running.includes(mname))

  async function toggleCoresident(name: string) {
    if (!brainsGroup) {
      showAlert("Keine brains-Gruppe", "Es existiert noch keine Ko-Residenz-Gruppe „brains“ in der Engine-Konfiguration. Lege sie erst über die Gruppen-Verwaltung an.")
      return
    }
    const inGroup = brainsMembers.includes(name)
    const next = inGroup ? brainsMembers.filter((x) => x !== name) : [...brainsMembers, name]
    try {
      await setGroup("brains", next, brainsGroup.swap ?? false, brainsGroup.persist ?? true)
      qc.invalidateQueries({ queryKey: qk.groups })
      reload()
    } catch (e: any) {
      showAlert("Fehler", `Ko-Residenz konnte nicht geändert werden: ${e.message || e}`)
    }
  }

  // UI state
  const [activeRoleForAssign, setActiveRoleForAssign] = useState<string | null>(null)
  const [roleRec, setRoleRec] = useState<RoleRecResp | null>(null)
  const [specModel, setSpecModel] = useState<ModelInfo | 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
  })

  async function doLoadModel(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 handleLoadModel(name: string) {
    // Warnung: Ein gruppenloses Modell lädt exklusiv und verdrängt das warme Hirn (brains-Ko-Residenz).
    if (brainsGroup && brainsWarm && !isCoresident(name)) {
      const warm = brainsMembers.filter((m) => running.includes(m)).map((m) => m.split("/").pop()).join(", ")
      showConfirm(
        "Verdrängt das Hirn?",
        `„${name.split("/").pop()}“ ist nicht in der Ko-Residenz-Gruppe „brains“. Beim Laden wirft es das aktuell warme Hirn (${warm}) raus — Lucy verliert Hirn bzw. Augen.\n\nTrotzdem exklusiv laden? Tipp: Mit dem 🧠-Schalter machst du das Modell dauerhaft ko-resident, dann bleiben beide warm.`,
        () => doLoadModel(name),
      )
      return
    }
    void doLoadModel(name)
  }

  async function handleUnloadModel(name: string) {
    const m = models.find((x) => x.name === name)
    if (m && isProtected(m.role)) {
      showAlert("Geschützt", `„${roleMeta(m.role).label}" ist lebenswichtig für Lucy und bleibt geladen. Zum Entladen erst im Experten-Modus die Rolle einem anderen Modell geben.`)
      return
    }
    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 {
      // Bei der Hirn-Rolle (hermes) läuft serverseitig der warm-bewusste Flow (Alias + brains-
      // Gruppe + ttl 0 + Hermes-Config + Gateway-Restart) und liefert ggf. eine Budget-Warnung.
      const res = await api<{ warning?: string | null }>(`/api/models/${encodeURIComponent(modelName)}/role`, {
        method: "POST",
        body: JSON.stringify({ role: role || null }),
      })
      reload()
      if (res?.warning) showAlert("Hirn gesetzt — Hinweis", res.warning)
    } catch (e: any) {
      showAlert("Fehler", `Fehler beim Zuweisen der Rolle: ${e.message || e}`)
    }
  }

  // Rollen-Modal öffnen + setup-bewusste Empfehlung holen (bestes installiertes Modell).
  function openRoleAssign(role: string) {
    setActiveRoleForAssign(role)
    setRoleRec(null)
    api<RoleRecResp>(`/api/roles/${encodeURIComponent(role)}/recommend`)
      .then((d) => setRoleRec(d))
      .catch(() => { /* Empfehlung optional — Modal funktioniert auch ohne */ })
  }

  async function handleSetCtx(name: string, cur: number | null) {
    // Setup-bewussten Optimalwert holen (Rolle/Params/Quant + aktuelles Setup).
    let auto: { ctx: number; gtt_gb: number; reserved_gb: number; budget_gb: number; mode: string } | null = null
    try {
      auto = await api(`/api/models/${encodeURIComponent(name)}/ctx/auto`)
    } catch { /* Auto optional — Prompt funktioniert auch ohne */ }

    const hint = auto
      ? `Optimal für dein Setup: ${(auto.ctx / 1024).toFixed(0)}k (${auto.ctx}) — ` +
        `GTT ${auto.gtt_gb} GB − reserviert ${auto.reserved_gb} GB (${auto.mode}) → ${auto.budget_gb} GB frei. ` +
        `»Auto« trägt diesen Wert ein.`
      : "Gib die gewünschte Kontextlänge in Tokens an:"

    showPrompt(
      "Kontextlänge anpassen",
      hint,
      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}`)
        }
      },
      undefined,
      auto ? { autoValue: String(auto.ctx), autoLabel: `Auto (${(auto.ctx / 1024).toFixed(0)}k)` } : undefined,
    )
  }

  async function handleDelete(name: string) {
    const m = models.find((x) => x.name === name)
    if (m && isProtected(m.role)) {
      showAlert("Geschützt", `„${roleMeta(m.role).label}" ist lebenswichtig für Lucy und kann nicht gelöscht werden. Weise die Rolle zuerst einem anderen Modell zu.`)
      return
    }
    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 handleBrainUpdate(repo: string) {
    const b = brain?.budget
    const warn = b && !b.fits
      ? `\n\n⚠ Speicher-Warnung: Dieses Brain (~${b.brain_gb} GB) bleibt immer resident (persistent). Zusammen mit dem größten on-demand-Modell (~${b.largest_ondemand_gb} GB) sprengt das das Budget (${b.gtt_gb} GB) → beim Laden von heavy/coder droht ein Überlauf. Erwäge ein kleineres Brain oder weniger Kontext.`
      : ""
    showConfirm(
      "Agent-Hirn aktualisieren?",
      `Neues Hermes-Modell '${repo.split("/").pop()}' herunterladen und als Agent-Hirn (Rolle hermes) setzen? Hermes nutzt danach automatisch das neue Modell.${warn}`,
      async () => {
        try {
          await api("/api/models/install", {
            method: "POST",
            body: JSON.stringify({ repo, role: "hermes", quant: "Q4_K_M", jinja: true }),
          })
          showAlert("Download gestartet", "Das neue Agent-Hirn wird geladen. Fortschritt oben.")
          reload()
        } catch (e: any) {
          showAlert("Fehler", `Update fehlgeschlagen: ${e.message || e}`)
        }
      }
    )
  }

  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>
    )
  }

  // Speicher-Pool = echtes GTT-Budget (unified memory, ~124 GB), nicht der alte 16-GB-Fallback.
  const runningWithInfo = models.filter((m) => running.includes(m.name))
  const totalRunningSize = runningWithInfo.reduce((acc, m) => acc + (m.size_bytes || 0), 0)
  const gttTotal = sysStatus?.gpu?.gtt_total || sysStatus?.gpu?.vram_total || 0
  const gttUsed = sysStatus?.gpu?.gtt_used || 0
  const virtualMax = 16 * 1024 ** 3 // Fallback, falls sysfs nichts liefert
  const capacity = gttTotal > 2 * 1024 ** 3
    ? gttTotal
    : (totalRunningSize > virtualMax ? totalRunningSize * 1.2 : virtualMax)

  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">
              Speicher-Pool: {fmtSize(totalRunningSize)} Gewichte{gttUsed > 0 ? ` · ${fmtSize(gttUsed)} real belegt (inkl. KV)` : ""} / {fmtSize(capacity)}
            </span>
            {expert && 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 ? `[${roleMeta(m.role).short}] ` : ""}{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.3: Immer-bereit-Set (Warm-Set / brains-Gruppe) — in Klartext, mit Budget */}
      <WarmSetManager />

      {/* ZONE B.4: Lane-Routing & Policy (UI-editierbar, hot-reload) — Experten-Detail */}
      {expert && <LaneEditor />}

      {/* 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">
          {expert ? "Gateway Steckplatz-Belegung (Slot-Zuweisung)" : "Wer macht was bei Lucy — zum Ändern antippen"}
        </div>
        <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
          {ROLES.map((role) => {
            const m = models.find((x) => x.role === role)
            const isWarm = m ? running.includes(m.name) : false

            return (
              <div 
                key={role}
                onClick={() => openRoleAssign(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">
                  <RoleLabel role={role} />
                  {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 B.6: Agent-Hirn (Hermes) — sichtbar + updatebar (NousResearch) */}
      {brain?.current && (
        <div className="rounded-2xl border border-indigo-500/30 bg-indigo-500/5 backdrop-blur-md p-5 shadow-lg shadow-black/10 space-y-3.5">
          <div className="flex items-center justify-between flex-wrap gap-2">
            <div className="flex items-center gap-2">
              <Bot className="h-4.5 w-4.5 text-indigo-400" />
              <span className="text-xs font-bold uppercase tracking-wider text-foreground">Agent-Hirn (Hermes)</span>
              {brain.current.version != null && (
                <span className="text-[9px] font-mono px-1.5 py-0.5 rounded bg-indigo-500/15 text-indigo-300 border border-indigo-500/25">v{brain.current.version}</span>
              )}
            </div>
            <button
              onClick={() => window.dispatchEvent(new CustomEvent("mc-navigate", { detail: { view: "agent" } }))}
              className="h-7 px-3 rounded-lg border border-indigo-500/30 bg-indigo-500/5 text-indigo-300 text-[9px] font-bold uppercase hover:bg-indigo-500/15 transition-all cursor-pointer"
              title="Hirn-Wechsel passiert jetzt zentral im Hermes-Tab"
            >
              Im Hermes-Tab wechseln →
            </button>
          </div>

          <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 rounded-xl bg-background/30 border border-border/30 p-3.5">
            <div className="min-w-0">
              <div className="text-xs font-mono font-bold text-foreground truncate" title={brain.current.name}>
                {brain.current.name.split("/").pop()}
              </div>
              <div className="text-[10px] text-muted-foreground/80 flex items-center gap-2 mt-0.5">
                <span>{brain.current.params_b ? `${brain.current.params_b}B` : "—"}</span>
                <span>•</span><span>{brain.current.quant || "GGUF"}</span>
                <span>•</span><span>{fmtSize(brain.current.size_bytes || 0)}</span>
              </div>
            </div>
            {brain.update_available && brain.recommended ? (
              <button
                onClick={() => handleBrainUpdate(brain.recommended!.repo)}
                className={cn(
                  "h-8 px-3 shrink-0 flex items-center justify-center gap-1.5 rounded-lg text-[10px] font-bold uppercase transition-all cursor-pointer shadow-md",
                  brain.budget && !brain.budget.fits
                    ? "bg-red-500 text-white hover:bg-red-400 shadow-red-500/10"
                    : "bg-amber-500 text-black hover:bg-amber-400 shadow-amber-500/10"
                )}
              >
                <Download className="h-3.5 w-3.5" /> Aktualisieren
              </button>
            ) : (
              <span className="h-8 px-3 shrink-0 flex items-center gap-1.5 text-[10px] font-bold text-emerald-400 uppercase tracking-wide bg-emerald-500/5 border border-emerald-500/15 rounded-lg select-none">
                <Check className="h-4 w-4" /> Neueste Generation
              </span>
            )}
          </div>

          {brain.update_available && brain.recommended && (
            <div className="text-[10px] text-amber-400/90 flex items-center gap-1.5">
              <span className="w-1.5 h-1.5 rounded-full bg-amber-400 animate-ping shrink-0" />
              Neuere Generation verfügbar: <span className="font-mono font-bold">{brain.recommended.name.replace(/-GGUF$/i, "")}</span>
              (v{brain.recommended.version}, {brain.recommended.params_b}B) — von NousResearch.
            </div>
          )}

          {brain.budget && (
            <div className={cn("text-[10px] flex items-start gap-1.5 leading-relaxed",
              brain.budget.fits ? "text-muted-foreground/80" : "text-red-400 font-semibold")}>
              <HardDrive className="h-3 w-3 shrink-0 mt-0.5" />
              <span>
                Always-On-Brain ~{brain.budget.brain_gb} GB + größtes on-demand (~{brain.budget.largest_ondemand_gb} GB)
                = {(brain.budget.brain_gb + brain.budget.largest_ondemand_gb).toFixed(1)} / {brain.budget.gtt_gb} GB
                {brain.budget.fits
                  ? " · passt gleichzeitig ✓"
                  : " · passt NICHT gleichzeitig ⚠ — heavy/coder würden das Brain verdrängen. Kleineres Brain oder weniger Kontext."}
              </span>
            </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 && <RoleLabel role={m.role} dense />}
                              {isProtected(m.role) && (
                                <span className="px-1.5 py-0.5 rounded bg-background/40 border border-border/40 text-[9px] font-semibold text-muted-foreground" title="Lebenswichtig für Lucy — geschützt vor Löschen/Entladen.">
                                  🔒 geschützt
                                </span>
                              )}
                              {expert && isCoresident(m.name) && (
                                <span className="px-1.5 py-0.5 rounded bg-fuchsia-500/10 border border-fuchsia-500/30 text-[9px] font-mono text-fuchsia-300 font-bold uppercase" title="Ko-resident in der brains-Gruppe — bleibt mit dem Hirn gemeinsam warm, verdrängt es nicht.">
                                  🧠 Ko-resident
                                </span>
                              )}
                              {expert && 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>
                              )}
                              {expert && (m.spec_active ? (
                                <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.spec_draft_model ? (
                                <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={`Draft gesetzt (${m.spec_draft_model}), aber INAKTIV — --spec-type fehlt oder Vocab inkompatibel. Über 'Spec' neu konfigurieren.`}>
                                  SPEC?
                                </span>
                              ) : null)}
                              {expert && 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">
                        {(() => {
                          const prot = isProtected(m.role)
                          const lockUnload = isRunning && prot
                          const disabled = (m.incomplete && !isRunning) || lockUnload
                          return (
                        <button
                          onClick={() => isRunning ? handleUnloadModel(m.name) : handleLoadModel(m.name)}
                          disabled={disabled}
                          title={lockUnload ? `„${roleMeta(m.role).label}" bleibt geladen (geschützt).` : undefined}
                          className={cn(
                            "flex-1 h-7 rounded-lg text-[9px] font-bold uppercase transition-all border flex items-center justify-center gap-1",
                            disabled
                              ? "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"
                          )}
                        >
                          {lockUnload ? "🔒 geladen" : isRunning ? "Entladen" : "Laden"}
                        </button>
                          )
                        })()}
                        {expert && (
                          <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>
                        )}
                        {expert && brainsGroup && (
                          <button
                            onClick={() => toggleCoresident(m.name)}
                            className={cn(
                              "h-7 px-2.5 rounded-lg border text-[9px] font-bold uppercase transition-colors cursor-pointer",
                              isCoresident(m.name)
                                ? "border-fuchsia-500/40 bg-fuchsia-500/10 text-fuchsia-300 hover:bg-fuchsia-500/20"
                                : "border-border/40 text-muted-foreground hover:bg-accent"
                            )}
                            title={isCoresident(m.name)
                              ? "Ko-resident (brains): bleibt mit dem Hirn gemeinsam warm. Klick = aus der Gruppe nehmen."
                              : "Zur brains-Gruppe hinzufügen — lädt dann ko-resident neben dem Hirn, statt es zu verdrängen."}
                          >
                            🧠
                          </button>
                        )}
                        {expert && (
                          <button
                            onClick={() => setSpecModel(m)}
                            className={cn(
                              "h-7 px-2.5 rounded-lg border text-[9px] font-bold uppercase transition-colors cursor-pointer flex items-center gap-1",
                              m.spec_active ? "border-emerald-500/30 text-emerald-400 hover:bg-emerald-500/10"
                                : m.spec_draft_model ? "border-amber-500/30 text-amber-400 hover:bg-amber-500/10"
                                : "border-border/40 text-muted-foreground hover:bg-accent"
                            )}
                            title="Speculative Draft konfigurieren (Vocab-geprüft)"
                          >
                            <Zap className="h-3 w-3" /> Spec
                          </button>
                        )}
                        <button
                          onClick={() => handleDelete(m.name)}
                          disabled={isProtected(m.role)}
                          className={cn(
                            "h-7 w-7 rounded-lg border border-border/40 flex items-center justify-center transition-colors",
                            isProtected(m.role)
                              ? "text-muted-foreground/40 cursor-not-allowed"
                              : "text-muted-foreground hover:text-red-400 hover:bg-red-500/5 cursor-pointer"
                          )}
                          aria-label="Modell löschen"
                          title={isProtected(m.role) ? `„${roleMeta(m.role).label}" ist geschützt und kann nicht gelöscht werden.` : "Modell löschen"}
                        >
                          <Trash2 className="h-3.5 w-3.5" aria-hidden="true" />
                        </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 && <RoleLabel role={m.role} dense className="shrink-0" />}
                          {isProtected(m.role) && (
                            <span className="px-1.5 py-0.5 rounded bg-background/40 border border-border/40 text-[8px] font-semibold text-muted-foreground shrink-0" title="Lebenswichtig für Lucy — geschützt vor Löschen/Entladen.">
                              🔒 geschützt
                            </span>
                          )}
                          {expert && isCoresident(m.name) && (
                            <span className="px-1.5 py-0.5 rounded bg-fuchsia-500/10 border border-fuchsia-500/30 text-[8px] font-mono text-fuchsia-300 font-bold uppercase shrink-0" title="Ko-resident in der brains-Gruppe — bleibt mit dem Hirn gemeinsam warm.">
                              🧠 Ko-resident
                            </span>
                          )}
                          {expert && 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>
                          )}
                          {expert && (m.spec_active ? (
                            <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.spec_draft_model ? (
                            <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={`Draft gesetzt (${m.spec_draft_model}), aber INAKTIV — --spec-type fehlt oder Vocab inkompatibel.`}>
                              SPEC?
                            </span>
                          ) : null)}
                          {expert && 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">
                        {(() => {
                          const prot = isProtected(m.role)
                          const lockUnload = isRunning && prot
                          const disabled = (m.incomplete && !isRunning) || lockUnload
                          return (
                        <button
                          onClick={() => isRunning ? handleUnloadModel(m.name) : handleLoadModel(m.name)}
                          disabled={disabled}
                          title={lockUnload ? `„${roleMeta(m.role).label}" bleibt geladen (geschützt).` : undefined}
                          className={cn(
                            "h-7 px-3 rounded-lg text-[9px] font-bold uppercase transition-all border flex items-center gap-1",
                            disabled
                              ? "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"
                          )}
                        >
                          {lockUnload ? "🔒 geladen" : isRunning ? "Entladen" : "Laden"}
                        </button>
                          )
                        })()}
                        {expert && (
                          <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>
                        )}
                        {expert && brainsGroup && (
                          <button
                            onClick={() => toggleCoresident(m.name)}
                            className={cn(
                              "h-7 px-2.5 rounded-lg border text-[9px] font-bold uppercase transition-colors cursor-pointer",
                              isCoresident(m.name)
                                ? "border-fuchsia-500/40 bg-fuchsia-500/10 text-fuchsia-300 hover:bg-fuchsia-500/20"
                                : "border-border/40 text-muted-foreground hover:bg-accent"
                            )}
                            title={isCoresident(m.name)
                              ? "Ko-resident (brains): bleibt mit dem Hirn gemeinsam warm. Klick = aus der Gruppe nehmen."
                              : "Zur brains-Gruppe hinzufügen — lädt dann ko-resident neben dem Hirn, statt es zu verdrängen."}
                          >
                            🧠
                          </button>
                        )}
                        {expert && (
                          <button
                            onClick={() => setSpecModel(m)}
                            className={cn(
                              "h-7 px-2.5 rounded-lg border text-[9px] font-bold uppercase transition-all cursor-pointer flex items-center gap-1",
                              m.spec_active ? "border-emerald-500/30 text-emerald-400 hover:bg-emerald-500/10"
                                : m.spec_draft_model ? "border-amber-500/30 text-amber-400 hover:bg-amber-500/10"
                                : "border-border/40 text-muted-foreground hover:bg-accent"
                            )}
                            title="Speculative Draft konfigurieren (Vocab-geprüft)"
                          >
                            <Zap className="h-3 w-3" /> Spec
                          </button>
                        )}
                        <button
                          onClick={() => handleDelete(m.name)}
                          disabled={isProtected(m.role)}
                          className={cn(
                            "h-7 w-7 rounded-lg flex items-center justify-center border border-border/40 transition-all",
                            isProtected(m.role)
                              ? "text-muted-foreground/40 cursor-not-allowed"
                              : "text-muted-foreground hover:text-red-400 hover:bg-red-500/5 cursor-pointer"
                          )}
                          aria-label="Modell löschen"
                          title={isProtected(m.role) ? `„${roleMeta(m.role).label}" ist geschützt und kann nicht gelöscht werden.` : "Modell löschen"}
                        >
                          <Trash2 className="h-3.5 w-3.5" aria-hidden="true" />
                        </button>
                      </div>
                    </div>
                  </div>
                )
              })
            )}
          </div>
        )}
      </div>

      {/* Role Assignment Modal */}
      {activeRoleForAssign && (
        <RoleAssignModal role={activeRoleForAssign} roleRec={roleRec} models={models}
          onAssign={(name) => { handleRoleChange(activeRoleForAssign, name); setActiveRoleForAssign(null) }}
          onClose={() => setActiveRoleForAssign(null)} />
      )}

      {specModel && (
        <SpecDraftModal
          model={specModel}
          onClose={() => setSpecModel(null)}
          onChanged={reload}
        />
      )}

      {dialogElement}
    </div>
  )
}
