import { useState, useCallback, useMemo } from 'react'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import { useI18n } from '@/lib/hooks/use-i18n'; import { useSettingsStore } from '@/lib/store/settings'; import { VIDEO_PROVIDERS } from '@/lib/media/video-providers'; import { Loader2, CheckCircle2, XCircle, Eye, EyeOff, Zap, Plus, Settings2, Trash2, } from 'lucide-react'; import { cn } from '@/lib/utils'; import type { VideoProviderId } from '@/lib/media/types'; interface VideoSettingsProps { selectedProviderId: VideoProviderId; } export function VideoSettings({ selectedProviderId }: VideoSettingsProps) { const { t } = useI18n(); const videoModelId = useSettingsStore((state) => state.videoModelId); const videoProvidersConfig = useSettingsStore((state) => state.videoProvidersConfig); const setVideoProviderConfig = useSettingsStore((state) => state.setVideoProviderConfig); const [showApiKey, setShowApiKey] = useState(false); const [testLoading, setTestLoading] = useState(false); const [testStatus, setTestStatus] = useState<'idle' | 'success' | 'error'>('idle'); const [testMessage, setTestMessage] = useState(''); // Model dialog state const [showModelDialog, setShowModelDialog] = useState(false); const [editingModelIndex, setEditingModelIndex] = useState(null); const [modelForm, setModelForm] = useState({ id: '', name: '' }); // Reset test state when provider changes (derived state pattern) const [prevSelectedProviderId, setPrevSelectedProviderId] = useState(selectedProviderId); if (selectedProviderId !== prevSelectedProviderId) { setPrevSelectedProviderId(selectedProviderId); setTestStatus('idle'); setTestMessage(''); } const currentConfig = videoProvidersConfig[selectedProviderId]; const currentProvider = VIDEO_PROVIDERS[selectedProviderId]; const builtInModels = currentProvider?.models || []; const customModels = useMemo( () => currentConfig?.customModels || [], [currentConfig?.customModels], ); const isServerConfigured = !!currentConfig?.isServerConfigured; const handleApiKeyChange = (apiKey: string) => { setVideoProviderConfig(selectedProviderId, { apiKey }); }; const handleBaseUrlChange = (baseUrl: string) => { setVideoProviderConfig(selectedProviderId, { baseUrl }); }; const handleTest = async () => { setTestLoading(true); setTestStatus('idle'); setTestMessage(''); try { const response = await fetch('/api/verify-video-provider', { method: 'POST', headers: { 'x-video-provider': selectedProviderId, 'x-video-model': videoModelId || '', 'x-api-key': currentConfig?.apiKey || '', 'x-base-url': currentConfig?.baseUrl || '', }, }); const data = await response.json(); if (data.success) { setTestStatus('success'); setTestMessage(t('settings.videoConnectivitySuccess')); } else { setTestStatus('error'); setTestMessage(`${t('settings.videoConnectivityFailed')}: ${data.message}`); } } catch (err) { setTestStatus('error'); setTestMessage(`${t('settings.videoConnectivityFailed')}: ${err}`); } finally { setTestLoading(false); } }; // Model CRUD const handleOpenAddModel = () => { setEditingModelIndex(null); setModelForm({ id: '', name: '' }); setShowModelDialog(true); }; const handleOpenEditModel = (index: number) => { setEditingModelIndex(index); setModelForm({ ...customModels[index] }); setShowModelDialog(true); }; const handleSaveModel = useCallback(() => { if (!modelForm.id.trim()) return; const newCustomModels = [...customModels]; if (editingModelIndex !== null) { newCustomModels[editingModelIndex] = { id: modelForm.id.trim(), name: modelForm.name.trim() || modelForm.id.trim(), }; } else { newCustomModels.push({ id: modelForm.id.trim(), name: modelForm.name.trim() || modelForm.id.trim(), }); } setVideoProviderConfig(selectedProviderId, { customModels: newCustomModels, }); setShowModelDialog(false); }, [modelForm, editingModelIndex, customModels, selectedProviderId, setVideoProviderConfig]); const handleDeleteModel = (index: number) => { const newCustomModels = customModels.filter((_, i) => i !== index); setVideoProviderConfig(selectedProviderId, { customModels: newCustomModels, }); }; return (
{/* Server-configured notice */} {isServerConfigured && (
{t('settings.serverConfiguredNotice')}
)} {/* API Key + Test inline */}
handleApiKeyChange(e.target.value)} className="h-8 pr-8" />
{testMessage && (
{testStatus === 'success' && } {testStatus === 'error' && }

{testMessage}

)}
{/* Base URL */}
handleBaseUrlChange(e.target.value)} placeholder={ currentConfig?.serverBaseUrl || currentProvider?.defaultBaseUrl || t('settings.enterCustomBaseUrl') } className="h-8" /> {(() => { const effectiveBaseUrl = currentConfig?.baseUrl || currentConfig?.serverBaseUrl || currentProvider?.defaultBaseUrl || ''; if (!effectiveBaseUrl) return null; return (

{t('settings.requestUrl')}: {effectiveBaseUrl}

); })()}
{/* Model list */}
{/* Built-in models */} {builtInModels.map((model) => (
{model.name}
{model.id}
))} {/* Custom models */} {customModels.map((model, index) => (
{model.name}
{model.id}
))}
{/* Add/Edit Model Dialog */} {editingModelIndex !== null ? t('settings.editModel') : t('settings.addNewModel')} {editingModelIndex !== null ? t('settings.editModel') : t('settings.addNewModel')}
setModelForm((prev) => ({ ...prev, id: e.target.value }))} placeholder="e.g. my-custom-model-v1" className="h-8 font-mono text-sm" />
setModelForm((prev) => ({ ...prev, name: e.target.value }))} placeholder="e.g. My Custom Model" className="h-8 text-sm" />
); }