import { useState, useEffect } from 'react'
import { Save, Disc, Cpu, Database, Globe, AlertCircle, CheckCircle, HardDrive, Wrench, Send, Tv } from 'lucide-react'
import { api } from '../lib/api'
import { useDarkMode } from '../context/ThemeContext'
import { useToast } from '../context/ToastContext'
import StorageMounts from '../components/StorageMounts'
import WorkerVerwaltung from '../components/WorkerVerwaltung'

interface SettingsState {
  tmdbApiKey: string
  tvdbApiKey: string
  omdbApiKey: string
  outputDir: string
  movieDir: string
  seriesDir: string
  musicDir: string
  ripAllTracks: boolean
  mainFeatureOnly: boolean
  autoEject: boolean
  autoRipStart: boolean
  notificationWebhook: string
  transcodeEnabled: boolean
  transcodePreset: string
  keepOriginal: boolean
  mediaServer: string
  jellyfinUrl: string
  jellyfinApiKey: string
  workDir: string
  makemkvAppKey: string
}

const defaultSettings: SettingsState = {
  tmdbApiKey: '',
  tvdbApiKey: '',
  omdbApiKey: '',
  outputDir: '/app/media',
  movieDir: 'movies',
  seriesDir: 'series',
  musicDir: 'music',
  ripAllTracks: true,
  mainFeatureOnly: false,
  autoEject: true,
  autoRipStart: false,
  notificationWebhook: '',
  transcodeEnabled: true,
  transcodePreset: 'H.265 MKV 1080p30',
  keepOriginal: false,
  mediaServer: 'none',
  jellyfinUrl: '',
  jellyfinApiKey: '',
  workDir: '',
  makemkvAppKey: '',
}

type SettingsTab = 'ripping' | 'verarbeitung' | 'worker' | 'speicherziele' | 'apis' | 'benachrichtigungen' | 'system'

interface WorkerInfo {
  name: string
  encoders: string[]
  info?: { makemkv?: string, handbrake?: string, makemkv_key?: string }
}

interface SystemInfo {
  api_version: string
  plaetze: { name: string, frei_gb: number, gesamt_gb: number }[]
  workers: WorkerInfo[]
  makemkv_key_ui: boolean
  webhook_gesetzt: boolean
}

import { MEDIA_SERVER_OPTIONEN } from '../lib/mediaServer'

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

export default function SettingsPage() {
  const [settings, setSettings] = useState<SettingsState>(defaultSettings)
  const [activeTab, setActiveTab] = useState<SettingsTab>('ripping')
  const [workers, setWorkers] = useState<WorkerInfo[]>([])
  const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null)
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [saved, setSaved] = useState(false)
  const [testBusy, setTestBusy] = useState(false)
  const [quellenStatus, setQuellenStatus] = useState<Record<string, string> | null>(null)
  const [quellenBusy, setQuellenBusy] = useState(false)
  const [updates, setUpdates] = useState<Record<string, { installiert?: string, verfuegbar?: string, update?: boolean }> | null>(null)
  const [updatesBusy, setUpdatesBusy] = useState(false)

  const updatesPruefen = async () => {
    setUpdatesBusy(true)
    try {
      const r = await api.get('/system/updates')
      setUpdates(r.data)
      if (r.data?.makemkv?.update) {
        toast('info', `MakeMKV ${r.data.makemkv.verfuegbar} ist verfügbar (installiert: ${r.data.makemkv.installiert})`)
      } else {
        toast('success', 'Update-Check abgeschlossen')
      }
    } catch {
      toast('error', 'Update-Check fehlgeschlagen (makemkv.com/GitHub nicht erreichbar?)')
    } finally {
      setUpdatesBusy(false)
    }
  }
  const { theme } = useDarkMode()
  const { toast } = useToast()

  const quellenPruefen = async () => {
    setQuellenBusy(true)
    try {
      const r = await api.get('/metadata/status')
      setQuellenStatus(r.data)
      const kaputt = Object.entries(r.data).filter(([, v]) => v === 'fehler')
      if (kaputt.length === 0) {
        toast('success', 'Metadaten-Quellen geprüft — alles in Ordnung')
      } else {
        toast('error', `Quelle mit Problem: ${kaputt.map(([k]) => k.toUpperCase()).join(', ')}`)
      }
    } catch {
      toast('error', 'Prüfung fehlgeschlagen — läuft die API?')
    } finally {
      setQuellenBusy(false)
    }
  }

  useEffect(() => {
    api.get('/capabilities')
      .then(r => setWorkers(r.data.workers || []))
      .catch(() => setWorkers([]))
    api.get('/system/info')
      .then(r => setSystemInfo(r.data))
      .catch(() => setSystemInfo(null))
  }, [])

  const webhookTesten = async () => {
    if (!settings.notificationWebhook) return
    setTestBusy(true)
    try {
      await api.post('/notifications/test', { url: settings.notificationWebhook })
      toast('success', 'Test-Nachricht gesendet — prüfe deinen Kanal!')
    } catch (e: any) {
      toast('error', e?.response?.data?.detail || 'Test fehlgeschlagen')
    } finally {
      setTestBusy(false)
    }
  }

  useEffect(() => {
    const loadSettings = async () => {
      try {
        const response = await api.get('/settings')
        // Leeres Objekt von der API = noch nichts gespeichert → Defaults behalten
        setSettings({ ...defaultSettings, ...response.data })
      } catch {
        setSettings(defaultSettings)
      } finally {
        setLoading(false)
      }
    }
    loadSettings()
  }, [])

  const handleChange = (field: keyof SettingsState, value: any) => {
    setSettings(prev => ({ ...prev, [field]: value }))
    setSaved(false)
  }

  const handleSave = async () => {
    setSaving(true)
    try {
      await api.post('/settings', settings)
      setSaved(true)
      toast('success', 'Einstellungen gespeichert')
      setTimeout(() => setSaved(false), 3000)
    } catch {
      toast('error', 'Speichern fehlgeschlagen — läuft die API?')
    } finally {
      setSaving(false)
    }
  }

  if (loading) {
    return (
      <div className="flex items-center justify-center min-h-[60vh]">
        <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600"></div>
      </div>
    )
  }

  return (
    <div className={`max-w-4xl space-y-6 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
      <div className="flex flex-col gap-2 transition-colors duration-300">
        <h1 className={`text-3xl font-bold ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Einstellungen</h1>
        <p className={`text-sm ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>Konfiguriere Rippy nach deinen Wünschen</p>
      </div>

      {saved && (
        <div className={`p-4 rounded-lg flex items-center gap-3 font-medium transition-colors duration-300 ${theme === 'dark' ? 'bg-emerald-900/30 border border-emerald-700 text-emerald-400' : 'bg-emerald-50 border border-emerald-200 text-emerald-700'}`}>
          <CheckCircle className="flex-shrink-0" size={24} />
          <span>Einstellungen erfolgreich gespeichert!</span>
        </div>
      )}

      <div className={`rounded-xl shadow-sm overflow-hidden transition-colors duration-300 ${theme === 'dark' ? 'bg-slate-800 border border-slate-700' : 'bg-white border border-slate-200'}`}>
        {/* Tabs — echte Navigation (vorher reine Dekoration ohne onClick) */}
        <div className={`flex transition-colors duration-300 ${theme === 'dark' ? 'border-slate-700' : 'border-slate-200'} border-b`}>
          <TabButton icon={Disc} label="Ripping" isActive={activeTab === 'ripping'} onClick={() => setActiveTab('ripping')} darkMode={theme === 'dark'} />
          <TabButton icon={Cpu} label="Verarbeitung" isActive={activeTab === 'verarbeitung'} onClick={() => setActiveTab('verarbeitung')} darkMode={theme === 'dark'} />
          <TabButton icon={Cpu} label="Worker" isActive={activeTab === 'worker'} onClick={() => setActiveTab('worker')} darkMode={theme === 'dark'} />
          <TabButton icon={HardDrive} label="Speicherziele" isActive={activeTab === 'speicherziele'} onClick={() => setActiveTab('speicherziele')} darkMode={theme === 'dark'} />
          <TabButton icon={Globe} label="APIs" isActive={activeTab === 'apis'} onClick={() => setActiveTab('apis')} darkMode={theme === 'dark'} />
          <TabButton icon={AlertCircle} label="Benachrichtigungen" isActive={activeTab === 'benachrichtigungen'} onClick={() => setActiveTab('benachrichtigungen')} darkMode={theme === 'dark'} />
          <TabButton icon={Wrench} label="System" isActive={activeTab === 'system'} onClick={() => setActiveTab('system')} darkMode={theme === 'dark'} />
        </div>

        {/* Content */}
        <div className="p-6 space-y-8 transition-colors duration-300">
          {/* Ripping Settings */}
          {activeTab === 'ripping' && <section>
            <h2 className={`text-lg font-semibold mb-4 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <Disc size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              Ripping-Einstellungen
            </h2>
            
            <div className="space-y-6 transition-colors duration-300">
              {/* ── Video: DVD · Blu-ray · 4K UHD ─────────────────────── */}
              <p className={`text-xs font-semibold uppercase tracking-wider ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                📀 Video — DVD · Blu-ray · 4K UHD
              </p>

              <div className={`flex items-center justify-between p-4 transition-colors duration-300 ${theme === 'dark' ? 'bg-slate-700/50 rounded-lg' : 'bg-slate-50 rounded-lg'}`}>
                <div className="flex items-center gap-3">
                  <div className={`p-2 rounded-lg transition-colors duration-300 ${theme === 'dark' ? 'bg-indigo-900/30 text-indigo-400' : 'bg-indigo-100 text-indigo-600'}`}>
                    <Disc size={20} />
                  </div>
                  <div>
                    <h3 className={`font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Vollautomatik: sofort rippen</h3>
                    <p className={`text-sm transition-colors duration-300 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                      Disc erkannt → Rip startet ohne Nachfrage in den passenden Schnellwahl-Ordner
                      (Serie → Serien, sonst Filme; CD → Musik). Aus = wie bisher per „Rippen starten"-Dialog.
                    </p>
                  </div>
                </div>
                <Toggle
                  checked={settings.autoRipStart}
                  onChange={(v) => handleChange('autoRipStart', v)}
                  darkMode={theme === 'dark'}
                />
              </div>

              <div className={`flex items-center justify-between p-4 transition-colors duration-300 ${theme === 'dark' ? 'bg-slate-700/50 rounded-lg' : 'bg-slate-50 rounded-lg'}`}>
                <div className="flex items-center gap-3">
                  <div className={`p-2 rounded-lg transition-colors duration-300 ${theme === 'dark' ? 'bg-purple-900/30 text-purple-400' : 'bg-purple-100 text-purple-600'}`}>
                    <Disc size={20} />
                  </div>
                  <div>
                    <h3 className={`font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Nur Hauptfeature</h3>
                    <p className={`text-sm transition-colors duration-300 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>Rippe bei DVDs/Blu-rays nur das Hauptfeature</p>
                  </div>
                </div>
                <Toggle
                  checked={settings.mainFeatureOnly}
                  onChange={(v) => handleChange('mainFeatureOnly', v)}
                  darkMode={theme === 'dark'}
                />
              </div>

              <p className={`text-xs px-1 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                🌐 Sprachen &amp; Untertitel: MakeMKV sichert grundsätzlich ALLE Ton-Spuren und
                Untertitel verlustfrei, und auch die Kompression behält alle (--all-audio /
                --all-subtitles) — gerade bei Animes gehen also weder O-Ton noch Subs verloren.
              </p>

              {/* ── Audio-CD ──────────────────────────────────────────── */}
              <p className={`text-xs font-semibold uppercase tracking-wider pt-2 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                🎵 Audio-CD
              </p>

              <div className={`flex items-center justify-between p-4 transition-colors duration-300 ${theme === 'dark' ? 'bg-slate-700/50 rounded-lg' : 'bg-slate-50 rounded-lg'}`}>
                <div className="flex items-center gap-3">
                  <div className={`p-2 rounded-lg transition-colors duration-300 ${theme === 'dark' ? 'bg-blue-900/30 text-blue-400' : 'bg-blue-100 text-blue-600'}`}>
                    <Disc size={20} />
                  </div>
                  <div>
                    <h3 className={`font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Alle Tracks rippen</h3>
                    <p className={`text-sm transition-colors duration-300 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>Rippe alle Tracks einer CD (FLAC + MusicBrainz-Tags)</p>
                  </div>
                </div>
                <Toggle
                  checked={settings.ripAllTracks}
                  onChange={(v) => handleChange('ripAllTracks', v)}
                  darkMode={theme === 'dark'}
                />
              </div>

              {/* ── Allgemein ─────────────────────────────────────────── */}
              <p className={`text-xs font-semibold uppercase tracking-wider pt-2 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                Allgemein
              </p>

              <div className={`flex items-center justify-between p-4 transition-colors duration-300 ${theme === 'dark' ? 'bg-slate-700/50 rounded-lg' : 'bg-slate-50 rounded-lg'}`}>
                <div className="flex items-center gap-3">
                  <div className={`p-2 rounded-lg transition-colors duration-300 ${theme === 'dark' ? 'bg-emerald-900/30 text-emerald-400' : 'bg-emerald-100 text-emerald-600'}`}>
                    <Disc size={20} />
                  </div>
                  <div>
                    <h3 className={`font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Automatischer Auswurf</h3>
                    <p className={`text-sm transition-colors duration-300 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>Disk nach erfolgreichem Ripping auswerfen</p>
                  </div>
                </div>
                <Toggle
                  checked={settings.autoEject}
                  onChange={(v) => handleChange('autoEject', v)}
                  darkMode={theme === 'dark'}
                />
              </div>

              {/* Media-Server: Rippy bereitet die Ablage aufs Zielsystem vor */}
              <div className={`p-4 rounded-lg ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
                <h3 className={`font-medium mb-1 flex items-center gap-2 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
                  <Tv size={18} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
                  Media-Server (Jellyfin &amp; Co.)
                </h3>
                <p className={`text-sm mb-3 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                  Rippy benennt fertige Rips als „Titel (Jahr)" und legt — je nach System —
                  movie.nfo + poster.jpg dazu. Dein Server erkennt den Film dann ohne Nacharbeit.
                </p>
                <div className="grid grid-cols-2 md:grid-cols-5 gap-2">
                  {MEDIA_SERVER_OPTIONEN.map(o => (
                    <button
                      key={o.wert}
                      onClick={() => handleChange('mediaServer', o.wert)}
                      title={o.hinweis}
                      className={`px-3 py-2 rounded-lg text-sm font-medium border transition-all ${
                        settings.mediaServer === o.wert
                          ? theme === 'dark'
                            ? 'bg-indigo-900/40 border-indigo-500 text-indigo-300'
                            : 'bg-indigo-50 border-indigo-600 text-indigo-700'
                          : theme === 'dark'
                            ? 'bg-slate-800 border-slate-600 text-slate-400 hover:border-slate-500'
                            : 'bg-white border-slate-300 text-slate-600 hover:border-slate-400'
                      }`}
                    >
                      {o.label}
                    </button>
                  ))}
                </div>
                <p className={`text-xs mt-2 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                  {MEDIA_SERVER_OPTIONEN.find(o => o.wert === settings.mediaServer)?.hinweis}
                </p>

                {/* Jellyfin/Emby: nach jedem fertigen Rip die Bibliothek scannen */}
                {(settings.mediaServer === 'jellyfin' || settings.mediaServer === 'emby') && (
                  <div className={`mt-4 pt-4 border-t space-y-3 ${theme === 'dark' ? 'border-slate-600' : 'border-slate-200'}`}>
                    <p className={`text-sm ${theme === 'dark' ? 'text-slate-300' : 'text-slate-600'}`}>
                      <strong>Bibliotheks-Refresh</strong> (optional): Trag Server-URL + API-Key ein,
                      dann stößt Rippy nach jedem fertigen Rip sofort einen Scan an — der Film
                      erscheint ohne Warten in {settings.mediaServer === 'jellyfin' ? 'Jellyfin' : 'Emby'}.
                      API-Key: Administration → API-Schlüssel → Neu.
                    </p>
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
                      <input
                        type="text"
                        value={settings.jellyfinUrl}
                        onChange={(e) => handleChange('jellyfinUrl', e.target.value)}
                        placeholder="http://192.168.178.50:8096"
                        className={`px-3 py-2 border rounded-lg text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'}`}
                      />
                      <div className="flex gap-2">
                        <input
                          type="password"
                          value={settings.jellyfinApiKey}
                          onChange={(e) => handleChange('jellyfinApiKey', e.target.value)}
                          placeholder="API-Key"
                          className={`flex-1 px-3 py-2 border rounded-lg text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'}`}
                        />
                        <button
                          onClick={async () => {
                            try {
                              await api.post('/mediaserver/refresh', {
                                url: settings.jellyfinUrl, api_key: settings.jellyfinApiKey,
                              })
                              toast('success', 'Verbunden — Bibliotheks-Scan wurde angestoßen!')
                            } catch (e: any) {
                              toast('error', e?.response?.data?.detail || 'Verbindung fehlgeschlagen')
                            }
                          }}
                          disabled={!settings.jellyfinUrl || !settings.jellyfinApiKey}
                          className="px-3 py-2 rounded-lg bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-700 transition-colors disabled:opacity-40"
                        >
                          Testen
                        </button>
                      </div>
                    </div>
                  </div>
                )}
              </div>
            </div>
          </section>}

          {/* Verarbeitung: Kompressions-Stufe nach dem Rip */}
          {activeTab === 'verarbeitung' && <section>
            <h2 className={`text-lg font-semibold mb-4 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <Cpu size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              Verarbeitung (Kompression)
            </h2>
            <p className={`text-sm mb-4 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
              MakeMKV rippt verlustfrei (der einzige Weg durch den Kopierschutz), HandBrake
              komprimiert danach auf Arbeitsgröße. Die Roh-Datei wird nach Erfolg gelöscht.
            </p>

            {/* Ehrliche Selbstauskunft: was können die Worker WIRKLICH? */}
            <div className={`rounded-lg p-4 mb-4 ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
              <p className={`text-sm font-medium mb-2 ${theme === 'dark' ? 'text-slate-200' : 'text-slate-700'}`}>Verfügbare Encoder</p>
              {workers.length === 0 ? (
                <p className={`text-sm ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>Kein Worker gemeldet.</p>
              ) : (
                workers.map(w => (
                  <div key={w.name} className="mb-1">
                    <span className={`text-xs font-mono mr-2 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>{w.name}</span>
                    {w.encoders.map(e => (
                      <span key={e} className={`inline-block text-xs px-2 py-0.5 rounded mr-1 ${e.startsWith('cpu') ? (theme === 'dark' ? 'bg-slate-800 text-slate-300' : 'bg-slate-200 text-slate-600') : 'bg-emerald-600/20 text-emerald-500 font-medium'}`}>
                        {ENCODER_LABELS[e] || e}
                      </span>
                    ))}
                  </div>
                ))
              )}
            </div>

            <div className="space-y-4 transition-colors duration-300">
              <div className={`flex items-center justify-between p-4 rounded-lg ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
                <div>
                  <h3 className={`font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Nach dem Rip komprimieren</h3>
                  <p className={`text-sm ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>x265 statt 40-GB-Rohdatei (empfohlen)</p>
                </div>
                <Toggle checked={settings.transcodeEnabled} onChange={(v) => handleChange('transcodeEnabled', v)} darkMode={theme === 'dark'} />
              </div>

              <div className="space-y-2">
                <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                  HandBrake-Preset
                </label>
                <select
                  value={settings.transcodePreset}
                  onChange={(e) => handleChange('transcodePreset', e.target.value)}
                  className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'}`}
                >
                  <option value="H.265 MKV 1080p30">H.265 MKV 1080p30 — klein &amp; modern (Standard)</option>
                  <option value="H.265 MKV 2160p60 4K">H.265 MKV 2160p60 4K — für UHD-Quellen</option>
                  <option value="HQ 1080p30 Surround">HQ 1080p30 Surround — H.264, maximale Kompatibilität</option>
                  <option value="Super HQ 1080p30 Surround">Super HQ 1080p30 Surround — größer, beste Qualität</option>
                </select>
              </div>

              <div className={`flex items-center justify-between p-4 rounded-lg ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
                <div>
                  <h3 className={`font-medium ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>Original behalten</h3>
                  <p className={`text-sm ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>Verlustfreie Roh-Datei zusätzlich aufheben (viel Speicher!)</p>
                </div>
                <Toggle checked={settings.keepOriginal} onChange={(v) => handleChange('keepOriginal', v)} darkMode={theme === 'dark'} />
              </div>

              {/* Arbeitsverzeichnis: 4K-UHD-Rohdaten (bis 100 GB) passen nicht
                  auf jede VM-Platte — hier auf eine große Freigabe umlegen */}
              <div className="space-y-2">
                <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                  Arbeitsverzeichnis für Roh-Rips (optional)
                </label>
                <input
                  type="text"
                  value={settings.workDir}
                  onChange={(e) => handleChange('workDir', e.target.value)}
                  placeholder="leer = /app/temp (Container-Platte)"
                  className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent font-mono text-sm ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'}`}
                />
                <p className={`text-xs ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                  Muss unter /app/media liegen (z. B. /app/media/nas-arbeit — Freigabe vorher unter
                  Speicherziele einhängen). Wichtig für 4K-UHD: Rohdaten sind bis 100 GB groß;
                  Rippy prüft den Platz VOR dem Rip und bricht sonst mit Klartext ab.
                  {systemInfo?.plaetze?.length ? (
                    <> Aktuell frei: {systemInfo.plaetze.map(p => `${p.name}: ${p.frei_gb} GB`).join(' · ')}</>
                  ) : null}
                </p>
              </div>
            </div>
          </section>}

          {/* Worker: Encoding-Maschinen im Netz */}
          {activeTab === 'worker' && <section>
            <h2 className={`text-lg font-semibold mb-4 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <Cpu size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              Encoding-Worker
            </h2>
            <WorkerVerwaltung />
          </section>}

          {/* Speicherziele: Netzwerk-Mounts aus dem UI */}
          {activeTab === 'speicherziele' && <section>
            <h2 className={`text-lg font-semibold mb-4 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <HardDrive size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              Speicherziele
            </h2>

            {/* Schnellwahl-Ordner: die drei Knöpfe im "Rippen starten"-Dialog */}
            <div className={`rounded-lg p-4 mb-6 border ${theme === 'dark' ? 'border-slate-700 bg-slate-800/50' : 'border-slate-200 bg-slate-50'}`}>
              <h3 className={`font-medium mb-1 flex items-center gap-2 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
                <Database size={16} className="text-indigo-500" /> Schnellwahl beim Rippen
              </h3>
              <p className={`text-xs mb-3 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                Beim Start eines Rips fragt Rippy „Wohin?" — diese drei Ordner erscheinen
                dort als 🎥/📺/🎵-Schnellwahl. Hier legst du nur fest, wie sie heißen.
              </p>
              <div className="grid grid-cols-3 gap-3">
                {([['movieDir', '🎥 Filme'], ['seriesDir', '📺 Serien'], ['musicDir', '🎵 Musik']] as const).map(([feld, label]) => (
                  <div key={feld}>
                    <label className={`block text-xs font-medium mb-1 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>{label}</label>
                    <input
                      type="text"
                      value={settings[feld]}
                      onChange={(e) => handleChange(feld, e.target.value)}
                      className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'}`}
                    />
                  </div>
                ))}
              </div>
            </div>

            <StorageMounts />
          </section>}

          {/* API Keys */}
          {activeTab === 'apis' && <section>
            <h2 className={`text-lg font-semibold mb-4 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <Globe size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              API-Schlüssel
            </h2>

            {/* Live-Prüfung: funktioniert der eingetragene Key WIRKLICH? */}
            <div className={`rounded-lg p-4 mb-4 flex flex-wrap items-center gap-3 ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
              <button
                onClick={quellenPruefen}
                disabled={quellenBusy}
                className="px-4 py-2 rounded-lg bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-700 transition-colors disabled:opacity-40"
              >
                {quellenBusy ? 'Prüfe…' : 'Verbindung prüfen'}
              </button>
              {quellenStatus ? (
                <div className="flex flex-wrap gap-2">
                  {Object.entries(quellenStatus).map(([quelle, status]) => (
                    <span
                      key={quelle}
                      className={`text-xs px-2.5 py-1 rounded-full font-medium ${
                        status === 'ok' ? 'bg-emerald-600/20 text-emerald-500'
                        : status === 'kein_key' ? (theme === 'dark' ? 'bg-slate-800 text-slate-400' : 'bg-slate-200 text-slate-500')
                        : 'bg-rose-600/20 text-rose-500'
                      }`}
                    >
                      {quelle.toUpperCase()}: {status === 'ok' ? '✓ funktioniert' : status === 'kein_key' ? 'kein Key' : '✗ Fehler'}
                    </span>
                  ))}
                </div>
              ) : (
                <span className={`text-xs ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                  Prüft live gegen TMDB/OMDb — nach dem Speichern eines neuen Keys hier klicken.
                  Beide TMDB-Key-Arten funktionieren (v3-Schlüssel und v4-Token).
                </span>
              )}
            </div>

            <div className="space-y-4 transition-colors duration-300">
              <div className="space-y-2 transition-colors duration-300">
                <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                  TMDB API Key
                </label>
                <input
                  type="password"
                  value={settings.tmdbApiKey}
                  onChange={(e) => handleChange('tmdbApiKey', e.target.value)}
                  className={`w-full px-3 py-2 ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'} border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all`}
                  placeholder="Dein TMDB API Key"
                />
                <p className={`text-xs ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                  Hol dir einen Key auf <a href="https://www.themoviedb.org/" target="_blank" rel="noopener noreferrer" className={`${theme === 'dark' ? 'text-indigo-400 hover:underline' : 'text-indigo-600 hover:underline'}`}>themoviedb.org</a>
                </p>
              </div>

              <div className="space-y-2 transition-colors duration-300">
                <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                  TVDb API Key
                </label>
                <input
                  type="password"
                  value={settings.tvdbApiKey}
                  onChange={(e) => handleChange('tvdbApiKey', e.target.value)}
                  className={`w-full px-3 py-2 ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'} border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all`}
                  placeholder="Dein TVDb API Key"
                />
              </div>

              <div className="space-y-2 transition-colors duration-300">
                <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                  OMDb API Key (Fallback)
                </label>
                <input
                  type="password"
                  value={settings.omdbApiKey}
                  onChange={(e) => handleChange('omdbApiKey', e.target.value)}
                  className={`w-full px-3 py-2 ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'} border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all`}
                  placeholder="Dein OMDb API Key"
                />
                <p className={`text-xs ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                  Zweite Quelle, wenn TMDB nichts findet — kostenloser Key auf <a href="https://www.omdbapi.com/apikey.aspx" target="_blank" rel="noopener noreferrer" className={`${theme === 'dark' ? 'text-indigo-400 hover:underline' : 'text-indigo-600 hover:underline'}`}>omdbapi.com</a>
                </p>
              </div>
            </div>
          </section>}

          {/* Webhook — mit Anleitung und Sofort-Test (Commander-Wunsch 24.07.) */}
          {activeTab === 'benachrichtigungen' && <section>
            <h2 className={`text-lg font-semibold mb-2 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <AlertCircle size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              Webhook-Benachrichtigungen
            </h2>
            <p className={`text-sm mb-4 ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
              Rippy meldet sich, sobald ein Job <strong>fertig</strong> ist, <strong>fehlschlägt</strong> oder
              <strong> abgebrochen</strong> wird — direkt in deinen Chat. Der Dienst wird an der URL
              automatisch erkannt, du musst nichts weiter einstellen.
            </p>

            {/* Schritt-für-Schritt: so kommst du an eine Webhook-URL */}
            <div className={`rounded-lg p-4 mb-4 space-y-3 text-sm ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
              <div>
                <p className={`font-medium ${theme === 'dark' ? 'text-slate-200' : 'text-slate-700'}`}>💬 Discord (einfachster Weg)</p>
                <p className={theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}>
                  Server → Kanal-Zahnrad → Integrationen → Webhooks → „Neuer Webhook" →
                  „Webhook-URL kopieren" und unten einfügen.
                </p>
              </div>
              <div>
                <p className={`font-medium ${theme === 'dark' ? 'text-slate-200' : 'text-slate-700'}`}>📱 ntfy (Push aufs Handy, ohne Account)</p>
                <p className={theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}>
                  ntfy-App installieren, ein Thema abonnieren (z. B. „rippy-tobi-4711") und unten
                  https://ntfy.sh/rippy-tobi-4711 eintragen. Thema = Passwort, also etwas Einmaliges wählen.
                </p>
              </div>
              <div>
                <p className={`font-medium ${theme === 'dark' ? 'text-slate-200' : 'text-slate-700'}`}>🔧 Slack / Eigenes</p>
                <p className={theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}>
                  Slack: „Incoming Webhook" in den App-Einstellungen anlegen. Alles andere
                  (Home Assistant, n8n, eigene Skripte) bekommt JSON: {'{'}"title", "message", "level"{'}'}.
                </p>
              </div>
            </div>

            <div className="space-y-2 transition-colors duration-300">
              <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                Webhook URL
              </label>
              <div className="flex gap-2">
                <input
                  type="text"
                  value={settings.notificationWebhook}
                  onChange={(e) => handleChange('notificationWebhook', e.target.value)}
                  className={`flex-1 px-3 py-2 ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'} border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all`}
                  placeholder="https://discord.com/api/webhooks/… oder https://ntfy.sh/mein-thema"
                />
                <button
                  onClick={webhookTesten}
                  disabled={!settings.notificationWebhook || testBusy}
                  className="flex items-center gap-2 px-4 py-2 rounded-lg bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-700 transition-colors disabled:opacity-40"
                >
                  <Send size={15} />
                  {testBusy ? 'Sende…' : 'Test senden'}
                </button>
              </div>
              <p className={`text-xs ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                „Test senden" prüft die Anbindung sofort — nicht vergessen, danach zu speichern,
                damit auch der Worker die URL kennt.
              </p>
            </div>
          </section>}

          {/* System: Kern-Werkzeuge, Versionen, MakeMKV-Key, Speicherplatz */}
          {activeTab === 'system' && <section>
            <h2 className={`text-lg font-semibold mb-4 flex items-center gap-2 transition-colors duration-300 ${theme === 'dark' ? 'text-slate-100' : 'text-slate-900'}`}>
              <Wrench size={20} className={theme === 'dark' ? 'text-indigo-400' : 'text-indigo-600'} />
              System &amp; Kern-Werkzeuge
            </h2>

            {/* Werkzeug-Versionen je Worker — ehrlich gemeldet, nicht behauptet */}
            <div className={`rounded-lg p-4 mb-4 ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
              <p className={`text-sm font-medium mb-2 ${theme === 'dark' ? 'text-slate-200' : 'text-slate-700'}`}>Installierte Werkzeuge</p>
              {!systemInfo || systemInfo.workers.length === 0 ? (
                <p className={`text-sm ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>Noch kein Worker gemeldet.</p>
              ) : (
                systemInfo.workers.map(w => (
                  <div key={w.name} className="flex flex-wrap items-center gap-2 mb-1.5">
                    <span className={`text-xs font-mono ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>{w.name}</span>
                    {w.info?.makemkv && (
                      <span className={`text-xs px-2 py-0.5 rounded ${theme === 'dark' ? 'bg-slate-800 text-slate-300' : 'bg-slate-200 text-slate-600'}`}>
                        MakeMKV {w.info.makemkv}
                      </span>
                    )}
                    {w.info?.handbrake && (
                      <span className={`text-xs px-2 py-0.5 rounded ${theme === 'dark' ? 'bg-slate-800 text-slate-300' : 'bg-slate-200 text-slate-600'}`}>
                        HandBrake {w.info.handbrake}
                      </span>
                    )}
                    {w.info?.makemkv_key && (
                      <span className={`text-xs px-2 py-0.5 rounded ${w.info.makemkv_key === 'keiner' ? 'bg-amber-600/20 text-amber-500' : 'bg-emerald-600/20 text-emerald-500'}`}>
                        {w.info.makemkv_key === 'ui' ? 'Beta-Key: aus dem UI' :
                         w.info.makemkv_key === 'env' ? 'Beta-Key: aus .env' :
                         'Kein Beta-Key (Blu-ray nur im Testmodus)'}
                      </span>
                    )}
                  </div>
                ))
              )}
              {systemInfo?.plaetze && systemInfo.plaetze.length > 0 && (
                <p className={`text-xs mt-3 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                  Speicherplatz: {systemInfo.plaetze.map(p => `${p.name}: ${p.frei_gb} von ${p.gesamt_gb} GB frei`).join(' · ')}
                </p>
              )}
            </div>

            {/* MakeMKV-Beta-Key: der Monats-Key, OHNE Rebuild aktualisierbar */}
            <div className="space-y-2">
              <label className={`block text-sm font-medium ${theme === 'dark' ? 'text-slate-300' : 'text-slate-700'}`}>
                MakeMKV Beta-Key
              </label>
              <input
                type="password"
                value={settings.makemkvAppKey}
                onChange={(e) => handleChange('makemkvAppKey', e.target.value)}
                className={`w-full px-3 py-2 ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'} border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all font-mono text-sm`}
                placeholder={'T-… (Forum-Thread „MakeMKV is free while in beta")'}
              />
              <p className={`text-xs ${theme === 'dark' ? 'text-slate-400' : 'text-slate-500'}`}>
                Der Key wechselt etwa monatlich (MakeMKV-Forum, Thread t=1053). Hier eintragen +
                speichern — er gilt ab dem <strong>nächsten Rip</strong>, ganz ohne Neustart oder Rebuild
                und schlägt den Key aus der .env. DVDs gehen immer auch ohne Key.
              </p>
              <p className={`text-xs ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                Die MakeMKV-<strong>Version</strong> selbst steckt im Worker-Image — Update per
                Rebuild: <code>docker compose build worker &amp;&amp; docker compose up -d worker</code> (siehe README).
              </p>
            </div>

            {/* Update-Check: Rippy MELDET Updates ehrlich — selbst updaten
                kann es nicht (die Versionen stecken im Worker-Image) */}
            <div className={`rounded-lg p-4 mt-6 ${theme === 'dark' ? 'bg-slate-700/50' : 'bg-slate-50'}`}>
              <div className="flex items-center justify-between mb-2">
                <p className={`text-sm font-medium ${theme === 'dark' ? 'text-slate-200' : 'text-slate-700'}`}>Update-Check</p>
                <button
                  onClick={updatesPruefen}
                  disabled={updatesBusy}
                  className="px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-medium hover:bg-indigo-700 transition-colors disabled:opacity-40"
                >
                  {updatesBusy ? 'Prüfe…' : 'Auf Updates prüfen'}
                </button>
              </div>
              {updates ? (
                <div className="space-y-2 text-sm">
                  <div className={updates.makemkv?.update ? 'text-amber-500' : (theme === 'dark' ? 'text-slate-300' : 'text-slate-600')}>
                    <strong>MakeMKV:</strong> installiert {updates.makemkv?.installiert || '—'},
                    aktuell {updates.makemkv?.verfuegbar || 'unbekannt'}
                    {updates.makemkv?.update && (
                      <span className="block text-xs mt-1">
                        Update: in der .env <code>MAKEMKV_VERSION={updates.makemkv.verfuegbar}</code> setzen,
                        dann auf der Rippy-Maschine <code>docker compose build worker &amp;&amp; docker compose up -d worker</code>.
                        Neue Version bringt auch die neueste Disc-Schlüssel-Datenbank mit.
                      </span>
                    )}
                  </div>
                  <div className={theme === 'dark' ? 'text-slate-300' : 'text-slate-600'}>
                    <strong>HandBrake:</strong> Docker-Worker {updates.handbrake?.installiert || '—'} (Debian-Paket),
                    neueste offizielle Version {updates.handbrake?.verfuegbar || 'unbekannt'}
                    <span className={`block text-xs mt-1 ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                      Im Docker-Worker kommt HandBrake aus Debian und hinkt der offiziellen Version
                      bewusst hinterher (stabil, keine Eigenbauten). Der native Windows-Worker nutzt
                      die aktuelle Version direkt.
                    </span>
                  </div>
                </div>
              ) : (
                <p className={`text-xs ${theme === 'dark' ? 'text-slate-500' : 'text-slate-400'}`}>
                  Prüft gegen makemkv.com und die HandBrake-GitHub-Releases (Ergebnis wird 12 h gemerkt).
                </p>
              )}
            </div>
          </section>}

          {/* Save Button — nicht im Worker-Tab: dort gibt es nichts zu
              speichern (Liste + Anbinde-Befehle), der Knopf verwirrte nur */}
          {activeTab !== 'worker' && (
          <div className={`flex items-center justify-end gap-4 pt-6 transition-colors duration-300 ${theme === 'dark' ? 'border-slate-700' : 'border-slate-200'} border-t`}>
            <button
              onClick={handleSave}
              disabled={saving}
              className="flex items-center gap-2 px-6 py-2.5 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
            >
              {saving ? (
                <>
                  <div className="animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent"></div>
                  Speichern...
                </>
              ) : (
                <>
                  <Save size={20} />
                  Einstellungen speichern
                </>
              )}
            </button>
          </div>
          )}
        </div>
      </div>
    </div>
  )
}

function TabButton({ icon: Icon, label, isActive, onClick, darkMode }: { icon: any, label: string, isActive: boolean, onClick: () => void, darkMode: boolean }) {
  const { theme } = useDarkMode()
  return (
    <button
      onClick={onClick}
      className={`px-6 py-3 text-sm font-medium transition-colors border-b-2 ${
        isActive
          ? `${darkMode ? 'border-indigo-500 text-indigo-400' : 'border-indigo-600 text-indigo-600'}`
          : `${darkMode ? 'border-transparent text-slate-400 hover:text-slate-300' : 'border-transparent text-slate-500 hover:text-slate-700'}`
      }`}
    >
      {label}
    </button>
  )
}

function Toggle({ checked, onChange, darkMode }: { checked: boolean, onChange: (v: boolean) => void, darkMode: boolean }) {
  const { theme } = useDarkMode()
  return (
    <button
      onClick={() => onChange(!checked)}
      className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
        checked ? 'bg-indigo-600' : darkMode ? 'bg-slate-600' : 'bg-slate-300'
      }`}
    >
      <span
        className={`${
          checked ? 'translate-x-6' : 'translate-x-1'
        } inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}
      />
    </button>
  )
}
