import { useMemo, useState } from "react"
import {
  Search, Power, PowerOff, Edit3, Trash2, Zap, HardDrive, Cpu, Lock, Brain, Check,
} from "lucide-react"
import { api, type ModelInfo } from "@/lib/api"
import { useModels, useSystemStatus, useGroups, useQueryClient, qk } from "@/lib/queries"
import { useDialog } from "@/lib/useDialog"
import { useExpertMode } from "@/lib/useExpertMode"
import { CapsChips } from "@/components/CapsChips"
import { RoleLabel, getBrandInfo } from "@/components/models/ModelBadges"
import { SpecDraftModal } from "@/components/models/SpecDraftModal"
import { ROLE_META, roleMeta } from "@/lib/roleMeta"
import { fmtSize, fmtCtx } from "@/lib/format"
import { cn } from "@/lib/utils"
import { MaschinenraumBar } from "./MaschinenraumBar"
import { roleBarColor } from "./roleColors"

const B = 1024 ** 3
const short = (name: string) => name.split("/").pop()?.replace(/\.gguf$/i, "") ?? name

// Modelle-Werkbank (Frontend v3): Maschinenraum-Speicherleiste als Hero oben, darunter
// Master/Detail — „links wählen, rechts verwalten". Reine Frontend-Neuordnung; alle
// Aktionen laufen über die bestehenden /api/models-Endpoints (wie im IST-Cockpit).
// Eingebettet als Haupt-Tab im Modell-Manager (Überschrift + Discover liefert ModelsView).
export function ModelsWorkbench() {
  const qc = useQueryClient()
  const { data: modelsResp, isLoading, error } = useModels()
  const { data: sys } = useSystemStatus()
  const { data: groupsResp } = useGroups()
  const { showAlert, showConfirm, showPrompt, dialogElement } = useDialog()
  const expert = useExpertMode()

  const models = modelsResp?.models ?? []
  const running = modelsResp?.running ?? []
  const isProtected = (role?: string | null) => !!roleMeta(role).protected

  const brainsGroup = groupsResp?.groups?.brains
  const brainsMembers = brainsGroup?.members ?? []
  const isCoresident = (name: string) => brainsMembers.includes(name)

  const [selName, setSelName] = useState<string | null>(null)
  const [query, setQuery] = useState("")
  const [filter, setFilter] = useState<"all" | "in_use">("all")
  const [specModel, setSpecModel] = useState<ModelInfo | null>(null)

  const reload = () => {
    qc.invalidateQueries({ queryKey: qk.models })
    qc.invalidateQueries({ queryKey: qk.routing })
    qc.invalidateQueries({ queryKey: qk.groups })
  }

  const runningInfo = models.filter((m) => running.includes(m.name))
  const gttTotal = sys?.gpu?.gtt_total || sys?.gpu?.vram_total || 0
  const gttUsed = sys?.gpu?.gtt_used || 0
  const capacity = gttTotal > 2 * B ? gttTotal : 124 * B

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase()
    return models
      .filter((m) => (filter === "in_use" ? !!m.role || running.includes(m.name) : true))
      .filter((m) => (q ? m.name.toLowerCase().includes(q) : true))
      .sort((a, b) => {
        const aw = running.includes(a.name) ? 0 : 1
        const bw = running.includes(b.name) ? 0 : 1
        if (aw !== bw) return aw - bw
        return short(a.name).localeCompare(short(b.name))
      })
  }, [models, running, filter, query])

  const selected = models.find((m) => m.name === selName) ?? null

  // ── Aktionen (IST-Logik) ───────────────────────────────────────────────────
  async function doLoad(name: string) {
    try { await api(`/api/models/${encodeURIComponent(name)}/load`, { method: "POST" }); reload() }
    catch (e: any) { showAlert("Fehler", `Laden fehlgeschlagen: ${e.message || e}`) }
  }
  async function handleLoad(name: string) {
    const brainsWarm = brainsMembers.some((m) => running.includes(m))
    if (brainsGroup && brainsWarm && !isCoresident(name)) {
      const warm = brainsMembers.filter((m) => running.includes(m)).map(short).join(", ")
      showConfirm("Verdrängt das Hirn?",
        `„${short(name)}" ist nicht ko-resident. Beim Laden wirft es das warme Hirn (${warm}) raus — Lucy verliert Hirn bzw. Augen.\n\nTrotzdem exklusiv laden?`,
        () => doLoad(name))
      return
    }
    void doLoad(name)
  }
  async function handleUnload(name: string) {
    const m = models.find((x) => x.name === name)
    if (m && isProtected(m.role)) {
      showAlert("Geschützt", `„${roleMeta(m.role).label}" ist lebenswichtig und bleibt geladen.`)
      return
    }
    try { await api(`/api/models/${encodeURIComponent(name)}/unload`, { method: "POST" }); reload() }
    catch (e: any) { showAlert("Fehler", `Entladen fehlgeschlagen: ${e.message || e}`) }
  }
  async function handleRole(role: string, modelName: string) {
    try {
      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("Rolle gesetzt — Hinweis", res.warning)
    } catch (e: any) { showAlert("Fehler", `Rolle zuweisen fehlgeschlagen: ${e.message || e}`) }
  }
  async function handleCtx(name: string, cur: number | null) {
    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 { /* optional */ }
    const hint = auto
      ? `Optimal für dein Setup: ${(auto.ctx / 1024).toFixed(0)}k (${auto.ctx}). »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", `Kontext setzen fehlgeschlagen: ${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}" kann nicht gelöscht werden. Weise die Rolle zuerst einem anderen Modell zu.`)
      return
    }
    showConfirm("Modell löschen?", `„${short(name)}" und alle GGUF-Dateien unwiderruflich von der Box löschen?`, async () => {
      try { await api(`/api/models/${encodeURIComponent(name)}`, { method: "DELETE" }); if (selName === name) setSelName(null); reload() }
      catch (e: any) { showAlert("Fehler", `Löschen fehlgeschlagen: ${e.message || e}`) }
    })
  }

  if (isLoading) return <div className="py-16 text-center text-xs text-muted-foreground">Werkbank wird geladen …</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 ({String(error)}).</div>

  return (
    <div className="space-y-5">
      <MaschinenraumBar
        running={runningInfo} capacityBytes={capacity} realUsedBytes={gttUsed}
        selected={selName} onSelect={setSelName}
      />

      <div className="grid gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.3fr)]">
        {/* Master — Liste */}
        <div className="mc-card p-4">
          <div className="mb-3 flex items-center gap-2">
            <div className="relative flex-1">
              <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/60" />
              <input
                value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Modell suchen …"
                className="h-8 w-full rounded-lg border border-border/40 bg-background/40 pl-8 pr-2 text-xs text-foreground placeholder:text-muted-foreground/50 focus:border-primary/50 focus:outline-none"
              />
            </div>
            <div className="flex rounded-lg border border-border/40 bg-background/30 p-0.5">
              {(["all", "in_use"] as const).map((f) => (
                <button key={f} onClick={() => setFilter(f)}
                  className={cn("rounded-md px-2 py-1 text-[9px] font-bold uppercase transition-all cursor-pointer",
                    filter === f ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground")}>
                  {f === "all" ? "Alle" : "In Benutzung"}
                </button>
              ))}
            </div>
          </div>

          <div className="max-h-[60vh] space-y-1.5 overflow-y-auto scrollbar-thin pr-1">
            {filtered.length === 0 ? (
              <div className="rounded-xl border border-dashed border-border/50 p-8 text-center text-xs text-muted-foreground">Keine Modelle.</div>
            ) : filtered.map((m) => {
              const warm = running.includes(m.name)
              const sel = selName === m.name
              const brand = getBrandInfo(m.name)
              const c = roleBarColor(m.role)
              return (
                <button key={m.name} onClick={() => setSelName(m.name)}
                  className={cn(
                    "flex w-full items-center gap-2.5 rounded-xl border p-2.5 text-left transition-all cursor-pointer",
                    sel ? "border-primary/60 bg-primary/10" : "border-border/40 bg-background/20 hover:border-primary/30 hover:bg-background/40",
                  )}>
                  <span className={cn("flex h-7 w-7 shrink-0 items-center justify-center rounded-lg border text-[10px] font-bold", brand.color)}>{brand.initial}</span>
                  <div className="min-w-0 flex-1">
                    <div className="truncate font-mono text-xs font-semibold text-foreground">{short(m.name)}</div>
                    <div className="mt-0.5 flex items-center gap-1.5">
                      {m.role && <span className={cn("h-2 w-2 rounded-sm", c.dot)} />}
                      <span className="text-[10px] text-muted-foreground">{m.role ? roleMeta(m.role).short : "keine Rolle"}</span>
                      <span className="text-[10px] text-muted-foreground/50">· {fmtSize(m.size_bytes)}</span>
                    </div>
                  </div>
                  {warm
                    ? <span className="flex shrink-0 items-center gap-1 text-[9px] font-bold uppercase text-emerald-400"><span className="h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse" />warm</span>
                    : m.incomplete
                      ? <span className="shrink-0 text-[9px] font-bold uppercase text-amber-400">⚠ fehlt</span>
                      : <span className="shrink-0 text-[9px] font-semibold uppercase text-muted-foreground/50">bereit</span>}
                </button>
              )
            })}
          </div>
        </div>

        {/* Detail — verwalten */}
        <div className="mc-card p-5">
          {!selected ? (
            <div className="flex h-full min-h-[16rem] flex-col items-center justify-center gap-2 text-center text-muted-foreground">
              <Cpu className="h-8 w-8 opacity-40" />
              <p className="text-sm font-semibold">Links ein Modell wählen</p>
              <p className="text-xs">Dann verwaltest du es hier — laden, Rolle, Kontext, löschen.</p>
            </div>
          ) : (
            <Detail
              m={selected} warm={running.includes(selected.name)} expert={expert}
              protectedRole={isProtected(selected.role)} coresident={isCoresident(selected.name)}
              onLoad={() => handleLoad(selected.name)} onUnload={() => handleUnload(selected.name)}
              onRole={(r) => handleRole(r, selected.name)} onCtx={() => handleCtx(selected.name, selected.ctx)}
              onSpec={() => setSpecModel(selected)} onDelete={() => handleDelete(selected.name)}
            />
          )}
        </div>
      </div>

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

function Detail({
  m, warm, expert, protectedRole, coresident, onLoad, onUnload, onRole, onCtx, onSpec, onDelete,
}: {
  m: ModelInfo; warm: boolean; expert: boolean; protectedRole: boolean; coresident: boolean
  onLoad: () => void; onUnload: () => void; onRole: (r: string) => void; onCtx: () => void; onSpec: () => void; onDelete: () => void
}) {
  const brand = getBrandInfo(m.name)
  const lockUnload = warm && protectedRole

  return (
    <div className="flex h-full flex-col gap-4">
      {/* Kopf */}
      <div className="flex items-start gap-3">
        <span className={cn("flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border text-sm font-bold", brand.color)}>{brand.initial}</span>
        <div className="min-w-0 flex-1">
          <h2 className="break-all font-mono text-sm font-bold text-foreground">{short(m.name)}</h2>
          <div className="mt-1.5 flex flex-wrap items-center gap-1.5">
            {m.role ? <RoleLabel role={m.role} /> : <span className="rounded border border-dashed border-border/50 px-1.5 py-0.5 text-[10px] text-muted-foreground">keine Rolle</span>}
            {protectedRole && <span className="rounded bg-background/40 px-1.5 py-0.5 text-[10px] text-muted-foreground" title="Lebenswichtig — geschützt"><Lock className="mr-0.5 inline h-3 w-3" />geschützt</span>}
            {coresident && <span className="rounded border border-fuchsia-500/30 bg-fuchsia-500/10 px-1.5 py-0.5 text-[10px] font-bold uppercase text-fuchsia-300"><Brain className="mr-0.5 inline h-3 w-3" />Ko-resident</span>}
            {warm && <span className="flex items-center gap-1 text-[10px] font-bold uppercase text-emerald-400"><span className="h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse" />warm</span>}
          </div>
        </div>
      </div>

      {/* Primär-Aktion: laden / entladen */}
      <button
        onClick={warm ? onUnload : onLoad}
        disabled={(m.incomplete && !warm) || lockUnload}
        className={cn(
          "flex h-11 w-full items-center justify-center gap-2 rounded-xl border text-sm font-bold transition-all cursor-pointer disabled:cursor-not-allowed disabled:opacity-50",
          warm ? "border-amber-500/40 bg-amber-500/10 text-amber-300 hover:bg-amber-500/20"
            : "border-primary/40 bg-primary/10 text-primary hover:bg-primary/20",
        )}
        title={lockUnload ? `„${roleMeta(m.role).label}" bleibt geladen (geschützt).` : undefined}
      >
        {warm ? <PowerOff className="h-4 w-4" /> : <Power className="h-4 w-4" />}
        {lockUnload ? "🔒 bleibt geladen" : warm ? "Entladen" : "Ins Warm-Set laden"}
      </button>

      {/* Rolle wählen */}
      <div className="rounded-xl border border-border/30 bg-background/20 p-3">
        <div className="mb-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">Rolle</div>
        <div className="flex flex-wrap gap-1.5">
          <RoleChip active={!m.role} onClick={() => onRole("")} dot="bg-slate-400" label="keine" />
          {ROLE_META.map((r) => (
            <RoleChip key={r.role} active={m.role === r.role} onClick={() => onRole(r.role)}
              dot={roleBarColor(r.role).dot} label={r.short} />
          ))}
        </div>
      </div>

      {/* Kennzahlen */}
      <div className="grid grid-cols-2 gap-2 text-xs">
        <Metric icon={HardDrive} label="Größe" value={fmtSize(m.size_bytes)} />
        <button onClick={onCtx} className="group flex items-center gap-2 rounded-lg border border-border/30 bg-background/20 p-2.5 text-left transition-colors hover:border-primary/40 cursor-pointer">
          <Edit3 className="h-4 w-4 text-primary/80" />
          <div className="min-w-0">
            <div className="text-[9px] font-semibold uppercase tracking-wider text-muted-foreground/60">Kontext · ändern</div>
            <div className="font-semibold text-foreground">{fmtCtx(m.ctx)}</div>
          </div>
        </button>
      </div>

      {/* Beschleuniger */}
      <div className="rounded-xl border border-border/30 bg-background/20 p-3">
        <div className="mb-2 flex items-center justify-between">
          <span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">Beschleuniger</span>
          {expert && (
            <button onClick={onSpec}
              className={cn("flex h-6 items-center gap-1 rounded-lg border px-2 text-[9px] font-bold uppercase transition-colors cursor-pointer",
                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")}>
              <Zap className="h-3 w-3" /> Spec
            </button>
          )}
        </div>
        <div className="flex flex-wrap items-center gap-1.5">
          {m.spec_active && <Tag tone="emerald" label="Spec-Decoding aktiv" />}
          {!m.spec_active && m.spec_draft_model && <Tag tone="amber" label="Spec inaktiv" />}
          {m.prompt_cache && <Tag tone="cyan" label="Prompt-Cache" />}
          {m.parallel_slots > 1 && <Tag tone="violet" label={`${m.parallel_slots} Slots`} />}
          {!m.spec_active && !m.spec_draft_model && !m.prompt_cache && m.parallel_slots <= 1 && (
            <span className="text-[11px] text-muted-foreground/60">keine aktiv</span>
          )}
        </div>
      </div>

      {/* Fähigkeiten */}
      <div className="flex flex-wrap gap-1"><CapsChips caps={m.capabilities} /></div>

      {/* Löschen */}
      <button onClick={onDelete} disabled={protectedRole}
        className={cn("mt-auto flex h-9 items-center justify-center gap-1.5 rounded-lg border text-xs font-semibold transition-colors",
          protectedRole ? "cursor-not-allowed border-border/30 text-muted-foreground/40"
            : "border-red-500/30 text-red-400 hover:bg-red-500/10 cursor-pointer")}>
        <Trash2 className="h-3.5 w-3.5" /> {protectedRole ? "geschützt — nicht löschbar" : "Modell löschen"}
      </button>
    </div>
  )
}

function RoleChip({ active, onClick, dot, label }: { active: boolean; onClick: () => void; dot: string; label: string }) {
  return (
    <button onClick={onClick}
      className={cn("flex items-center gap-1.5 rounded-lg border px-2 py-1 text-[10px] font-semibold transition-all cursor-pointer",
        active ? "border-primary/60 bg-primary/15 text-foreground" : "border-border/40 bg-background/20 text-muted-foreground hover:border-primary/30")}>
      <span className={cn("h-2 w-2 rounded-sm", dot)} />
      {label}
      {active && <Check className="h-3 w-3 text-primary" />}
    </button>
  )
}

function Metric({ icon: Icon, label, value }: { icon: typeof HardDrive; label: string; value: string }) {
  return (
    <div className="flex items-center gap-2 rounded-lg border border-border/30 bg-background/20 p-2.5">
      <Icon className="h-4 w-4 text-primary/80" />
      <div className="min-w-0">
        <div className="text-[9px] font-semibold uppercase tracking-wider text-muted-foreground/60">{label}</div>
        <div className="font-semibold text-foreground">{value}</div>
      </div>
    </div>
  )
}

function Tag({ tone, label }: { tone: "emerald" | "amber" | "cyan" | "violet"; label: string }) {
  const cls = {
    emerald: "bg-emerald-500/10 text-emerald-400 border-emerald-500/20",
    amber: "bg-amber-500/10 text-amber-400 border-amber-500/20",
    cyan: "bg-cyan-500/10 text-cyan-400 border-cyan-500/20",
    violet: "bg-violet-500/10 text-violet-400 border-violet-500/20",
  }[tone]
  return <span className={cn("rounded border px-1.5 py-0.5 text-[10px] font-semibold", cls)}>{label}</span>
}
