import { useState, useEffect } from 'react'
import { Disc, Cpu, Globe, Tv, CheckCircle, ArrowRight, HardDrive, AlertTriangle } from 'lucide-react'
import { api } from '../lib/api'
import { MEDIA_SERVER_OPTIONEN } from '../lib/mediaServer'
import { PRESET_KEINE, schwacheEncoderCpu } from '../lib/encoder'
import { Button } from './ui/Button'
import { Input, Select } from './ui/Input'

interface WorkerInfo {
  name: string
  encoders: string[]
  online?: boolean
  info?: { cpu_kerne?: string; cpu_simd?: string; cpu_modell?: string }
}

interface GeraetInfo {
  id: string
  name: string
  status: string
}

interface PlatzInfo {
  name: string
  frei_gb: number
  gesamt_gb: number
}

const ENCODER_LABELS: Record<string, string> = {
  'cpu-x264': 'CPU · H.264 (x264)',
  'cpu-x265': 'CPU · H.265 (x265)',
  'cpu-av1': 'CPU · AV1 (SVT-AV1)',
  'vaapi': 'Hardware · VAAPI (AMD/Intel)',
  'nvenc': 'Hardware · NVENC (NVIDIA)',
}

// Unter diesem Wert lohnt der Hinweis auf die Ablage: eine einzelne Blu-ray
// braucht roh rund 40 GB, eine 4K-UHD bis 100 GB.
const PLATZ_WARNUNG_GB = 60

/** Was beim Abschliessen gespeichert wird — abhängig davon, was die Maschine kann. */
function presetsFuer(schwach: boolean) {
  if (schwach) {
    // Gemessen auf einer CPU ohne AVX2: 4K-HEVC = 28-55 h pro Film. Also 4K
    // verlustfrei behalten und für den Rest H.264 nehmen (deutlich schneller
    // als H.265, dafür etwas größer).
    return {
      transcodePreset: 'HQ 1080p30 Surround',
      transcodePresetBluray: 'HQ 1080p30 Surround',
      transcodePresetDvd: 'HQ 576p25 Surround',
      transcodePresetUhd: PRESET_KEINE,
    }
  }
  return {
    transcodePreset: 'H.265 MKV 1080p30',
    transcodePresetBluray: 'H.265 MKV 1080p30',
    transcodePresetDvd: 'H.265 MKV 576p25',
    transcodePresetUhd: 'H.265 MKV 2160p60 4K',
  }
}

export default function FirstRunWizard({ onDone }: { onDone: () => void }) {
  const [tmdbKey, setTmdbKey] = useState('')
  const [omdbKey, setOmdbKey] = useState('')
  const [mediaServer, setMediaServer] = useState('jellyfin')
  const [transcodeEnabled, setTranscodeEnabled] = useState(true)
  const [workers, setWorkers] = useState<WorkerInfo[]>([])
  const [geraete, setGeraete] = useState<GeraetInfo[]>([])
  const [plaetze, setPlaetze] = useState<PlatzInfo[]>([])
  const [geladen, setGeladen] = useState(false)
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [keyWarnung, setKeyWarnung] = useState<string | null>(null)

  // Wiederholt laden, bis Worker UND Laufwerk da sind: beim allerersten Start
  // läuft der Worker-Container oft noch hoch. Ohne das stand hier dauerhaft
  // „Noch kein Worker gemeldet" und der Nutzer wusste nicht, ob er warten soll.
  useEffect(() => {
    let laeuft = true
    const laden = async () => {
      const [caps, devs, info] = await Promise.allSettled([
        api.get('/capabilities'),
        api.get('/devices'),
        api.get('/system/info'),
      ])
      if (!laeuft) return
      if (caps.status === 'fulfilled') setWorkers(caps.value.data?.workers || [])
      if (devs.status === 'fulfilled') setGeraete(devs.value.data || [])
      if (info.status === 'fulfilled') setPlaetze(info.value.data?.plaetze || [])
      setGeladen(true)
    }
    laden()
    const takt = setInterval(laden, 5000)
    return () => { laeuft = false; clearInterval(takt) }
  }, [])

  const schwach = schwacheEncoderCpu(workers)
  const presets = presetsFuer(schwach)
  const encoderWorker = workers.filter(w => w.encoders.length > 0)
  const platz = plaetze.length > 0 ? Math.min(...plaetze.map(p => p.frei_gb)) : null

  const abschliessen = async () => {
    setSaving(true)
    setError(null)
    setKeyWarnung(null)
    try {
      const bestehende = (await api.get('/settings')).data || {}
      await api.post('/settings', {
        ...bestehende,
        ...(tmdbKey.trim() ? { tmdbApiKey: tmdbKey.trim() } : {}),
        ...(omdbKey.trim() ? { omdbApiKey: omdbKey.trim() } : {}),
        mediaServer,
        transcodeEnabled,
        ...presets,
      })
      // Erst SPEICHERN, dann prüfen: /metadata/status liest die Keys aus der
      // Datenbank, nicht aus dem Formular. Ein falsch kopierter Key fällt so
      // sofort auf, statt erst beim ersten Rip als „Unknown Disc".
      if (tmdbKey.trim() || omdbKey.trim()) {
        try {
          const s = (await api.get('/metadata/status')).data || {}
          const kaputt = Object.entries(s)
            .filter(([, v]) => v === 'fehler')
            .map(([k]) => k.toUpperCase())
          if (kaputt.length > 0) {
            setKeyWarnung(
              `${kaputt.join(' und ')} hat den Key nicht angenommen — vermutlich ein `
              + 'Tippfehler beim Kopieren. Rippy laeuft trotzdem, die Titel heissen dann '
              + 'nur wie das Disc-Label. Nachbessern: Einstellungen → APIs.'
            )
            setSaving(false)
            return  // nicht wegklicken, damit die Warnung gelesen wird
          }
        } catch {
          // Prüfung selbst kaputt → kein Grund, die Einrichtung zu blockieren
        }
      }
      await api.post('/setup/complete')
      onDone()
    } catch {
      setError('Speichern fehlgeschlagen — läuft die API? (Seite neu laden hilft meist.)')
      setSaving(false)
    }
  }

  const trotzdemWeiter = async () => {
    setSaving(true)
    try {
      await api.post('/setup/complete')
      onDone()
    } catch {
      setError('Speichern fehlgeschlagen — läuft die API?')
      setSaving(false)
    }
  }

  return (
    <div className="min-h-screen flex items-center justify-center p-6 bg-slate-100 dark:bg-slate-950">
      <div className="w-full max-w-2xl rounded-2xl shadow-2xl overflow-hidden bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800">
        <div className="bg-gradient-to-r from-amber-500 via-indigo-600 to-purple-700 p-8 text-white">
          <div className="flex items-center gap-3 mb-2">
            <Disc size={32} className="animate-disc-spin" />
            <h1 className="text-2xl font-bold">Willkommen bei Rippy</h1>
          </div>
          <p className="opacity-90">
            Einmalige Einrichtung — dauert keine zwei Minuten. Du kannst nichts kaputt
            machen: alles ist später unter Einstellungen änderbar.
          </p>
        </div>

        <div className="p-8 space-y-8">
          {/* ---- Was Rippy gerade sieht ---------------------------------- */}
          <section>
            <h2 className="flex items-center gap-2 text-lg font-semibold mb-3 text-slate-900 dark:text-slate-100">
              <HardDrive size={18} className="text-amber-500" /> Was Rippy gerade sieht
            </h2>
            <div className="rounded-xl border border-slate-200 dark:border-slate-800 divide-y divide-slate-200 dark:divide-slate-800 overflow-hidden">
              <Zeile
                titel="Laufwerk"
                geladen={geladen}
                gut={geraete.length > 0}
                gutText={geraete.map(g => g.name).join(', ')}
                schlechtText="Kein optisches Laufwerk gefunden. Rippy kann dann nur komprimieren, nicht rippen. Prüfe, ob das Laufwerk angeschlossen und (bei einer VM) durchgereicht ist."
              />
              <Zeile
                titel="Encoding-Worker"
                geladen={geladen}
                gut={encoderWorker.length > 0}
                gutText={encoderWorker.map(w => {
                  const kerne = w.info?.cpu_kerne
                  const simd = w.info?.cpu_simd
                  const zusatz = [kerne ? `${kerne} Kerne` : '', simd && simd !== 'unbekannt' ? simd : '']
                    .filter(Boolean).join(', ')
                  return zusatz ? `${w.name} (${zusatz})` : w.name
                }).join(' · ')}
                schlechtText="Noch kein Worker gemeldet. Beim ersten Start dauert das bis zu einer Minute — diese Anzeige aktualisiert sich selbst. Bleibt es dabei, läuft der Worker-Container nicht."
              />
              <Zeile
                titel="Freier Platz"
                geladen={geladen}
                gut={platz === null || platz >= PLATZ_WARNUNG_GB}
                gutText={platz === null ? '—' : `${platz.toFixed(0)} GB`}
                schlechtText={`Nur ${platz?.toFixed(0)} GB frei. Eine Blu-ray braucht roh rund 40 GB, eine 4K-UHD bis 100 GB. Lege die Ablage besser auf eine NAS-Freigabe (Einstellungen → Speicherziele).`}
              />
            </div>
          </section>

          {/* ---- Metadaten ---------------------------------------------- */}
          <section>
            <h2 className="flex items-center gap-2 text-lg font-semibold mb-3 text-slate-900 dark:text-slate-100">
              <Globe size={18} className="text-amber-500" /> Metadaten-Erkennung
            </h2>
            <div className="space-y-3">
              {/* Bewusst SICHTBAR statt type=password: Das sind kopierte Keys,
                  keine Passwoerter — und einen Tippfehler sieht man in Punkten
                  nicht. Geprueft wird direkt nach dem Speichern. */}
              <Input
                label="TMDB API-Key (empfohlen)"
                value={tmdbKey}
                onChange={e => setTmdbKey(e.target.value)}
                placeholder="Kostenlos auf themoviedb.org — hier einfügen"
              />
              <Input
                label="OMDb API-Key (optional, zweite Quelle)"
                value={omdbKey}
                onChange={e => setOmdbKey(e.target.value)}
                placeholder="Kostenlos auf omdbapi.com"
              />
              <p className="text-xs text-slate-500 dark:text-slate-400">
                Ohne Keys rippt Rippy trotzdem — Discs heißen dann nur wie ihr Volume-Label.
                Beide Keys werden direkt nach dem Speichern geprüft.
              </p>
            </div>
          </section>

          {/* ---- Media-Server ------------------------------------------- */}
          <section>
            <h2 className="flex items-center gap-2 text-lg font-semibold mb-3 text-slate-900 dark:text-slate-100">
              <Tv size={18} className="text-amber-500" /> Dein Media-Server
            </h2>
            <p className="text-sm mb-3 text-slate-500 dark:text-slate-400">
              Rippy benennt fertige Rips als „Titel (Jahr)" und legt für Jellyfin/Emby/Kodi
              zusätzlich movie.nfo + poster.jpg dazu.
            </p>
            <div className="grid grid-cols-2 md:grid-cols-5 gap-2">
              {MEDIA_SERVER_OPTIONEN.map(o => (
                <button
                  key={o.wert}
                  type="button"
                  onClick={() => setMediaServer(o.wert)}
                  title={o.hinweis}
                  className={`px-3 py-2 rounded-xl text-sm font-medium border transition-all ${
                    mediaServer === o.wert
                      ? 'bg-amber-500/20 border-amber-500 text-amber-600 dark:text-amber-300 font-semibold'
                      : 'bg-slate-50 dark:bg-slate-800 border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-400 hover:border-slate-300 dark:hover:border-slate-600'
                  }`}
                >
                  {o.label}
                </button>
              ))}
            </div>
            <p className="text-xs mt-2 text-slate-500 dark:text-slate-400">
              {MEDIA_SERVER_OPTIONEN.find(o => o.wert === mediaServer)?.hinweis}
            </p>
          </section>

          {/* ---- Verarbeitung ------------------------------------------- */}
          <section>
            <h2 className="flex items-center gap-2 text-lg font-semibold mb-3 text-slate-900 dark:text-slate-100">
              <Cpu size={18} className="text-amber-500" /> Verarbeitung
            </h2>

            <label className="flex items-start gap-3 mb-3 text-sm text-slate-700 dark:text-slate-300">
              <input
                type="checkbox"
                checked={transcodeEnabled}
                onChange={e => setTranscodeEnabled(e.target.checked)}
                className="w-4 h-4 mt-0.5 accent-amber-500 rounded"
              />
              <span>
                Nach dem Rip auf Arbeitsgröße komprimieren
                <span className="block text-xs text-slate-500 dark:text-slate-400">
                  Empfohlen — ohne Kompression braucht jede Blu-ray rund 40 GB.
                </span>
              </span>
            </label>

            {transcodeEnabled && (
              <div className={`rounded-xl p-4 border ${
                schwach
                  ? 'bg-amber-500/10 border-amber-500/30'
                  : 'bg-slate-50 dark:bg-slate-950/80 border-slate-200 dark:border-slate-800'
              }`}>
                {/* Der Kern dieser Seite: Die Empfehlung folgt der GEMESSENEN
                    Rechenleistung. Vorher stand hier H.265 als Standard - auf
                    einer CPU ohne AVX2 sind das 28-55 Stunden je 4K-Film, und
                    genau das ist am 25.07.2026 passiert. */}
                {schwach ? (
                  <>
                    <p className="text-sm font-medium flex items-start gap-2 text-amber-700 dark:text-amber-300">
                      <AlertTriangle size={16} className="mt-0.5 flex-shrink-0" />
                      <span>Rippy hat deine Rechenleistung gemessen und passt die Wahl an.</span>
                    </p>
                    <p className="text-xs mt-2 text-amber-700/90 dark:text-amber-300/90">
                      Keiner deiner Worker kann AVX2 — die Vektorbefehle, von denen H.265
                      lebt. 4K in H.265 würde hier <strong>ein bis zwei Tage pro Film</strong>
                      {' '}dauern. Deshalb wird eingestellt:
                    </p>
                  </>
                ) : (
                  <p className="text-sm font-medium text-slate-700 dark:text-slate-300">
                    Deine Worker sind schnell genug für H.265 — Rippy stellt ein:
                  </p>
                )}
                <ul className="mt-2 space-y-1 text-xs text-slate-600 dark:text-slate-400">
                  <li>
                    <strong>4K-UHD:</strong>{' '}
                    {presets.transcodePresetUhd === PRESET_KEINE
                      ? 'nicht komprimieren, verlustfrei behalten (20–100 GB je Film)'
                      : presets.transcodePresetUhd}
                  </li>
                  <li><strong>Blu-ray:</strong> {presets.transcodePresetBluray}</li>
                  <li><strong>DVD:</strong> {presets.transcodePresetDvd}</li>
                </ul>
                <p className="mt-2 text-xs text-slate-500 dark:text-slate-400">
                  Alles einzeln änderbar unter Einstellungen → Verarbeitung.
                </p>
              </div>
            )}

            {encoderWorker.length > 0 && (
              <div className="mt-3 flex flex-wrap gap-1">
                {encoderWorker.flatMap(w => w.encoders).filter((e, i, a) => a.indexOf(e) === i).map(e => (
                  <span key={e} className={`text-xs px-2 py-0.5 rounded font-medium ${
                    e.startsWith('cpu')
                      ? 'bg-slate-200 dark:bg-slate-800 text-slate-600 dark:text-slate-300'
                      : 'bg-emerald-500/15 text-emerald-600 dark:text-emerald-400'
                  }`}>
                    {ENCODER_LABELS[e] || e}
                  </span>
                ))}
              </div>
            )}
          </section>

          {keyWarnung && (
            <div className="p-4 rounded-xl bg-amber-500/10 border border-amber-500/30">
              <p className="text-sm text-amber-700 dark:text-amber-300">{keyWarnung}</p>
              <div className="flex gap-2 mt-3">
                <Button variant="secondary" size="sm" onClick={() => setKeyWarnung(null)}>
                  Key korrigieren
                </Button>
                <Button variant="secondary" size="sm" onClick={trotzdemWeiter} disabled={saving}>
                  Trotzdem fertigstellen
                </Button>
              </div>
            </div>
          )}

          {error && (
            <p className="text-sm p-3 rounded-lg bg-rose-500/10 border border-rose-500/30 text-rose-600 dark:text-rose-400">
              {error}
            </p>
          )}

          <Button
            variant="amber"
            size="lg"
            onClick={abschliessen}
            disabled={saving}
            className="w-full"
          >
            {saving ? 'Speichern…' : <>Los geht's <ArrowRight size={18} /></>}
          </Button>

          <p className="text-xs text-center flex items-center justify-center gap-1 text-slate-500 dark:text-slate-400">
            <CheckCircle size={12} /> Läuft komplett lokal — keine Cloud, keine Telemetrie.
          </p>
        </div>
      </div>
    </div>
  )
}

/** Eine Zeile im „Was Rippy gerade sieht"-Kasten: gruen, wenn es passt, sonst
 *  bernstein MIT Handlungsanweisung. Nie nur ein Kreuz ohne Erklaerung. */
function Zeile({ titel, geladen, gut, gutText, schlechtText }: {
  titel: string
  geladen: boolean
  gut: boolean
  gutText: string
  schlechtText: string
}) {
  if (!geladen) {
    return (
      <div className="flex items-center gap-3 p-3">
        <span className="w-2 h-2 rounded-full bg-slate-300 dark:bg-slate-600 animate-pulse flex-shrink-0" />
        <span className="text-sm text-slate-500 dark:text-slate-400">{titel} — wird geprüft…</span>
      </div>
    )
  }
  return (
    <div className="flex items-start gap-3 p-3">
      <span className={`w-2 h-2 mt-1.5 rounded-full flex-shrink-0 ${gut ? 'bg-emerald-500' : 'bg-amber-500'}`} />
      <div className="min-w-0">
        <p className="text-sm text-slate-700 dark:text-slate-300">
          <span className="font-medium">{titel}:</span>{' '}
          {gut ? gutText : <span className="text-amber-600 dark:text-amber-400">nicht bereit</span>}
        </p>
        {!gut && <p className="text-xs mt-0.5 text-amber-700/90 dark:text-amber-300/90">{schlechtText}</p>}
      </div>
    </div>
  )
}
