import { useEffect, useRef, useState } from "react"
import { Upload, Link2, ExternalLink, Check, Sparkles, Volume2, Loader2 } from "lucide-react"
import { saveUploadedVrm, loadUploadedVrm } from "@/lib/voice/vrmStore"

// Avatar selbst aussuchen (Galerie + .vrm-Upload + URL) + Stimm-Auswahl.
// Stimm-Engines: ElevenLabs (Premium, eigene Stimme) + Edge (gratis, nativ-deutsch). Auswahl in localStorage.

interface GalleryItem { id: string; label: string; url: string; note?: string }

// Verifiziert: 200 + Access-Control-Allow-Origin:* (im Browser ladbar).
const GALLERY: GalleryItem[] = [
  { id: "sample-a", label: "VRoid Sample A", url: "https://raw.githubusercontent.com/madjin/vrm-samples/master/vroid/stable/AvatarSample_A.vrm", note: "Anime, weiblich" },
  { id: "sample-b", label: "VRoid Sample B", url: "https://raw.githubusercontent.com/madjin/vrm-samples/master/vroid/stable/AvatarSample_B.vrm", note: "Anime, männlich" },
  { id: "pixiv", label: "Pixiv Demo", url: "https://raw.githubusercontent.com/pixiv/three-vrm/dev/packages/three-vrm/examples/models/VRM1_Constraint_Twist_Sample.vrm", note: "VRM1-Testmodell" },
]

export const DEFAULT_AVATAR = GALLERY[0].url

interface Voice { engine: string; id: string; label: string }

// Nur die zwei Engines, die wir wirklich nutzen.
const ENGINES = ["elevenlabs", "edge"] as const
const ENGINE_LABEL: Record<string, string> = {
  elevenlabs: "ElevenLabs (premium)",
  edge: "Edge (natürlich · gratis)",
}

export function AvatarPicker({ avatarUrl, onAvatarChange }: {
  avatarUrl: string; onAvatarChange: (url: string) => void
}) {
  const [urlInput, setUrlInput] = useState("")
  const [voices, setVoices] = useState<Voice[]>([])
  const [engine, setEngine] = useState(localStorage.getItem("mc_voice_engine") || "elevenlabs")
  const [voice, setVoice] = useState(localStorage.getItem("mc_voice_voice") || "")
  const [previewing, setPreviewing] = useState(false)
  const fileRef = useRef<HTMLInputElement>(null)
  const previewAudio = useRef<HTMLAudioElement | null>(null)

  const saveVoice = (eng: string, v: string) => {
    setEngine(eng); setVoice(v)
    localStorage.setItem("mc_voice_engine", eng)
    localStorage.setItem("mc_voice_voice", v)
  }

  // Stimmen vom Sidecar holen. WICHTIG: nie auf leerer Stimme bleiben — ElevenLabs' „Standardstimme"
  // (Rachel) ist eine Library-Voice, die das Free-Tier per API NICHT nutzen darf (402). Darum bei
  // leerer Auswahl automatisch die erste echte Stimme der aktiven Engine wählen.
  useEffect(() => {
    fetch("/api/voice/voices")
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((d) => {
        const list: Voice[] = d.voices || []
        setVoices(list)
        if (!voice) {
          const first = list.find((v) => v.engine === engine)
          if (first) saveVoice(engine, first.id)
        }
      })
      .catch(() => setVoices([]))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // „Probe hören": festen Satz mit aktueller Engine+Stimme abspielen.
  const playPreview = async () => {
    if (previewing) return
    setPreviewing(true)
    try {
      const r = await fetch("/api/voice/tts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ text: "Hallo! So klingt diese Stimme auf Deutsch.", engine, voice }),
      })
      if (!r.ok) throw new Error(`TTS ${r.status}`)
      const url = URL.createObjectURL(await r.blob())
      previewAudio.current?.pause()
      const a = new Audio(url)
      previewAudio.current = a
      a.onended = () => URL.revokeObjectURL(url)
      await a.play()
    } catch (e) {
      console.error("Probe fehlgeschlagen:", e)
    } finally {
      setPreviewing(false)
    }
  }

  // Hochgeladenes VRM nach Reload wiederherstellen.
  useEffect(() => {
    if (localStorage.getItem("mc_voice_avatar_uploaded") === "1") {
      loadUploadedVrm().then((buf) => {
        if (buf) onAvatarChange(URL.createObjectURL(new Blob([buf], { type: "model/gltf-binary" })))
      })
    }
  }, [onAvatarChange])

  const pickGallery = (url: string) => {
    localStorage.setItem("mc_voice_avatar_url", url)
    localStorage.removeItem("mc_voice_avatar_uploaded")
    onAvatarChange(url)
  }

  const onUpload = async (file: File) => {
    const buf = await file.arrayBuffer()
    await saveUploadedVrm(buf)
    localStorage.setItem("mc_voice_avatar_uploaded", "1")
    localStorage.removeItem("mc_voice_avatar_url")
    onAvatarChange(URL.createObjectURL(new Blob([buf], { type: "model/gltf-binary" })))
  }

  const loadUrl = () => {
    const u = urlInput.trim()
    if (u) pickGallery(u)
  }

  // Beim Engine-Wechsel direkt die erste Stimme der neuen Engine wählen (nie leer/„Standardstimme").
  const pickEngine = (eng: string) => {
    const first = voices.find((v) => v.engine === eng)
    saveVoice(eng, first?.id || "")
  }

  const voicesForEngine = voices.filter((v) => v.engine === engine)
  const elKeyMissing = engine === "elevenlabs" && voicesForEngine.length === 0

  return (
    <div className="space-y-5 text-sm">
      {/* Galerie */}
      <div>
        <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">Avatar</div>
        <div className="space-y-1.5">
          {GALLERY.map((g) => {
            const active = avatarUrl === g.url
            return (
              <button
                key={g.id}
                onClick={() => pickGallery(g.url)}
                className={`flex w-full items-center justify-between rounded-md border px-3 py-2 text-left transition-colors ${
                  active ? "border-primary/50 bg-primary/10 text-primary" : "border-border/40 hover:bg-accent"
                }`}
              >
                <span>
                  <span className="font-medium">{g.label}</span>
                  {g.note && <span className="ml-2 text-[11px] text-muted-foreground">{g.note}</span>}
                </span>
                {active && <Check className="h-4 w-4" />}
              </button>
            )
          })}
        </div>
      </div>

      {/* Eigenes Modell */}
      <div className="space-y-2">
        <input
          ref={fileRef}
          type="file"
          accept=".vrm,model/gltf-binary"
          className="hidden"
          onChange={(e) => { const f = e.target.files?.[0]; if (f) void onUpload(f) }}
        />
        <button
          onClick={() => fileRef.current?.click()}
          className="flex w-full items-center gap-2 rounded-md border border-border/40 bg-background/40 px-3 py-2 hover:bg-accent transition-colors"
        >
          <Upload className="h-4 w-4" /> Eigenes .vrm hochladen
        </button>
        <div className="flex gap-1.5">
          <input
            value={urlInput}
            onChange={(e) => setUrlInput(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && loadUrl()}
            placeholder="…oder VRM-URL einfügen"
            className="min-w-0 flex-1 rounded-md border border-border/40 bg-background/40 px-2.5 py-2 text-xs outline-none focus:border-primary/50"
          />
          <button onClick={loadUrl} className="rounded-md border border-border/40 bg-background/40 px-2.5 hover:bg-accent" title="Laden">
            <Link2 className="h-4 w-4" />
          </button>
        </div>
        <a
          href="https://hub.vroid.com/en/characters"
          target="_blank"
          rel="noopener"
          className="flex items-center gap-1.5 text-xs text-primary/80 hover:text-primary"
        >
          <ExternalLink className="h-3.5 w-3.5" /> Mehr Avatare auf VRoid Hub (kostenlos) → herunterladen & hochladen
        </a>
      </div>

      {/* Stimme */}
      <div>
        <div className="mb-2 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
          <Sparkles className="h-3.5 w-3.5" /> Stimme
        </div>
        {voices.length === 0 ? (
          <div className="rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs text-amber-300">
            Voice-Dienst nicht erreichbar — Stimmen werden geladen, sobald der Sidecar läuft.
          </div>
        ) : (
          <div className="space-y-2">
            <div className="grid grid-cols-2 gap-1.5">
              {ENGINES.map((eng) => (
                <button
                  key={eng}
                  onClick={() => pickEngine(eng)}
                  className={`rounded-md border px-2.5 py-1.5 text-xs transition-colors ${
                    engine === eng ? "border-primary/50 bg-primary/10 text-primary" : "border-border/40 hover:bg-accent"
                  }`}
                >
                  {ENGINE_LABEL[eng]}
                </button>
              ))}
            </div>
            <select
              value={voice}
              onChange={(e) => saveVoice(engine, e.target.value)}
              className="w-full rounded-md border border-border/40 bg-background/40 px-2.5 py-2 text-xs outline-none focus:border-primary/50"
            >
              {voicesForEngine.map((v) => (
                <option key={v.id} value={v.id}>{v.label}</option>
              ))}
            </select>
            <button
              onClick={playPreview}
              disabled={previewing || elKeyMissing}
              className="flex w-full items-center justify-center gap-2 rounded-md border border-primary/40 bg-primary/10 px-2.5 py-2 text-xs text-primary hover:bg-primary/20 transition-colors disabled:opacity-60"
            >
              {previewing ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Volume2 className="h-3.5 w-3.5" />}
              {previewing ? "Spielt …" : "Probe hören"}
            </button>
            {engine === "elevenlabs" && !elKeyMissing && (
              <p className="text-[11px] text-muted-foreground">
                ElevenLabs: deine eigene Stimme, sauberes Deutsch, schnell. Nutze NUR eigene Stimmen —
                Library-Stimmen sperrt das Free-Tier per API.
              </p>
            )}
            {elKeyMissing && (
              <p className="text-[11px] text-amber-300">
                Keine ElevenLabs-Stimmen — Key in <code>~/.hermes/.env</code> fehlt, oder noch keine eigene Stimme angelegt.
              </p>
            )}
            {engine === "edge" && (
              <p className="text-[11px] text-muted-foreground">
                Edge: native deutsche Stimmen, gratis & ohne Key. Cloud (Text → Microsoft).
              </p>
            )}
          </div>
        )}
      </div>
    </div>
  )
}
