import { useState } from "react"
import { X, Check, Zap, AlertTriangle } from "lucide-react"
import { api, type ModelInfo, type DraftInfo } from "@/lib/api"
import { useDrafts } from "@/lib/queries"
import { fmtSize } from "@/lib/format"
import { cn } from "@/lib/utils"

/**
 * Idiotensichere Speculative-Decoding-Konfiguration für EIN Modell.
 * Zeigt nur VOCAB-KOMPATIBLE Drafts als wählbar; inkompatible werden gesperrt
 * und mit Begründung angezeigt. So kann nie ein kaputter Draft gesetzt werden
 * (der das Modell beim Laden scheitern ließe).
 */
export function SpecDraftModal({
  model, onClose, onChanged,
}: { model: ModelInfo; onClose: () => void; onChanged: () => void }) {
  const { data, isLoading } = useDrafts(model.gguf_path)
  const [busy, setBusy] = useState<string | null>(null)
  const [err, setErr] = useState("")

  const tv = data?.target_vocab
  const drafts = data?.drafts ?? []
  const compatibles = drafts.filter((d) => d.compatible === true)
  const currentFile = model.spec_draft_model

  async function apply(draftPath: string | null) {
    setBusy(draftPath ?? "__clear__")
    setErr("")
    try {
      await api(`/api/models/${encodeURIComponent(model.name)}/draft`, {
        method: "POST",
        body: JSON.stringify({ draft_path: draftPath }),
      })
      onChanged()
      onClose()
    } catch (e: any) {
      setErr(String(e?.message || e))
      setBusy(null)
    }
  }

  const vocabLabel = (v?: { pre: string | null; n_vocab: number | null } | null) =>
    v ? `${v.pre ?? "?"} · ${v.n_vocab?.toLocaleString() ?? "?"} Tokens` : "—"

  return (
    <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-lg 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 flex items-center gap-2">
            <Zap className="h-4 w-4" /> Speculative Draft
          </h3>
          <button onClick={onClose} className="p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer">
            <X className="h-4 w-4" />
          </button>
        </div>

        <div className="text-xs text-muted-foreground leading-relaxed">
          Beschleunigt die Token-Generierung mit einem kleinen "Draft"-Modell. Voraussetzung:
          der Draft muss den <strong className="text-foreground">exakt gleichen Tokenizer (Vocab)</strong> haben
          wie das Modell — sonst lehnt llama.cpp es ab.
        </div>

        {/* Ziel-Vocab */}
        <div className="rounded-lg border border-border/40 bg-background/30 px-3 py-2 text-[11px] font-mono flex items-center justify-between">
          <span className="text-muted-foreground">{model.name.split("/").pop()?.replace(/\.gguf$/i, "")}</span>
          <span className="text-foreground">Vocab: {vocabLabel(tv)}</span>
        </div>

        {/* Aktueller Zustand */}
        {model.spec_active && currentFile && (
          <div className="rounded-lg border border-emerald-500/30 bg-emerald-500/5 px-3 py-2 flex items-center justify-between gap-2">
            <span className="text-[11px] text-emerald-400 font-mono flex items-center gap-1.5 truncate">
              <Check className="h-3.5 w-3.5 shrink-0" /> Aktiv: {currentFile}
            </span>
            <button
              onClick={() => apply(null)}
              disabled={busy !== null}
              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 shrink-0 cursor-pointer disabled:opacity-50"
            >
              Deaktivieren
            </button>
          </div>
        )}

        {!data?.target_exists && (
          <div className="rounded-lg border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-[11px] text-amber-400 flex items-center gap-2">
            <AlertTriangle className="h-3.5 w-3.5 shrink-0" />
            Modell-GGUF noch nicht vorhanden — Spec-Draft ist nach dem Download konfigurierbar.
          </div>
        )}

        {/* Draft-Liste */}
        <div className="space-y-1.5 max-h-64 overflow-y-auto pr-1">
          {isLoading ? (
            <div className="text-xs text-muted-foreground py-6 text-center">Prüfe Vocab-Kompatibilität…</div>
          ) : drafts.length === 0 ? (
            <div className="text-[11px] text-muted-foreground border border-dashed border-border/50 rounded-lg p-4 text-center">
              Keine Draft-Modelle in <code className="font-mono">/srv/models/drafts</code>.
              Lade ein kleines same-family-Modell (z.B. Qwen3-0.6B) und lege es dort ab.
            </div>
          ) : (
            drafts.map((d: DraftInfo) => {
              const isCurrent = d.filename === currentFile
              const ok = d.compatible === true
              return (
                <div
                  key={d.path}
                  className={cn(
                    "rounded-lg border px-3 py-2 flex items-center justify-between gap-2 text-left",
                    ok ? "border-border/40 bg-background/20" : "border-border/20 bg-background/10 opacity-60",
                    isCurrent && "border-primary/40 bg-primary/10",
                  )}
                >
                  <div className="min-w-0">
                    <div className="text-[11px] font-mono font-semibold text-foreground truncate flex items-center gap-1.5">
                      {d.filename}
                      {d.mtp && (
                        <span
                          className="shrink-0 rounded bg-indigo-500/15 px-1.5 py-0.5 text-[8px] font-bold uppercase tracking-wider text-indigo-400 border border-indigo-500/25"
                          title="MTP-Kopf (Multi-Token-Prediction) — by-construction vocab-identisch, höchste Akzeptanzrate"
                        >
                          MTP
                        </span>
                      )}
                    </div>
                    <div className="text-[9px] text-muted-foreground font-mono">
                      {fmtSize(d.size_bytes)} · Vocab: {vocabLabel(d.vocab)}
                    </div>
                  </div>
                  {ok ? (
                    isCurrent ? (
                      <span className="text-[9px] font-bold uppercase text-primary flex items-center gap-1 shrink-0"><Check className="h-3.5 w-3.5" /> Aktiv</span>
                    ) : (
                      <button
                        onClick={() => apply(d.path)}
                        disabled={busy !== null}
                        className="h-7 px-3 rounded-lg border border-emerald-500/30 bg-emerald-500/5 hover:bg-emerald-500/15 text-emerald-400 text-[9px] font-bold uppercase shrink-0 cursor-pointer disabled:opacity-50"
                      >
                        Aktivieren
                      </button>
                    )
                  ) : (
                    <span
                      className="text-[9px] font-bold uppercase text-amber-400/80 flex items-center gap-1 shrink-0"
                      title={d.compatible === false
                        ? `Inkompatibel: Tokenizer/Vocab weicht ab (Draft ${d.vocab?.pre}/${d.vocab?.n_vocab} ≠ Modell ${tv?.pre}/${tv?.n_vocab}).`
                        : "Kompatibilität nicht prüfbar (Datei fehlt)."}
                    >
                      <AlertTriangle className="h-3.5 w-3.5" /> {d.compatible === false ? "Vocab ≠" : "n/a"}
                    </span>
                  )}
                </div>
              )
            })
          )}
        </div>

        {/* Hinweis, wenn Drafts da sind aber keiner kompatibel */}
        {!isLoading && data?.target_exists && drafts.length > 0 && compatibles.length === 0 && (
          <div className="rounded-lg border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-[11px] text-amber-400 leading-relaxed">
            Kein vocab-kompatibler Draft verfügbar — Speculative Decoding ist für dieses Modell nicht möglich.
            Es braucht einen Draft mit identischem Tokenizer (pre=<span className="font-mono">{tv?.pre}</span>,
            n_vocab=<span className="font-mono">{tv?.n_vocab?.toLocaleString()}</span>).
          </div>
        )}

        {err && <div className="text-[10px] text-red-400 font-mono">{err}</div>}
      </div>
    </div>
  )
}
