import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import type { MediaFile } from './types';
import { GenerationStatus } from './types';
import FileUploader from './components/FileUploader';
import MediaItem from './components/MediaItem';
import { generateCaption, refineCaption, checkCaptionQuality } from './services/geminiService';
import { generateCaptionQwen, refineCaptionQwen, checkQualityQwen } from './services/qwenService';
import { sendComfyPrompt } from './services/comfyService';
import { DownloadIcon, SparklesIcon, WandIcon, LoaderIcon, CopyIcon, UploadCloudIcon, XIcon, CheckCircleIcon, AlertTriangleIcon, StopIcon, TrashIcon } from './components/Icons';
import { DEFAULT_COMFY_WORKFLOW } from './constants/defaultWorkflow';

declare const process: {
  env: { API_KEY?: string; [key: string]: string | undefined; }
};

declare global {
  interface AIStudio {
    hasSelectedApiKey: () => Promise<boolean>;
    openSelectKey: () => Promise<void>;
  }
  interface Window { JSZip: any; aistudio?: AIStudio; }
}

type ApiProvider = 'gemini' | 'qwen';
type OSType = 'windows' | 'linux';

const GEMINI_MODELS = [
    { id: 'gemini-3-pro-preview', name: 'Gemini 3 Pro (High Quality)' },
    { id: 'gemini-3-flash-preview', name: 'Gemini 3 Flash (Fast)' },
    { id: 'gemini-2.5-pro-preview-09-2025', name: 'Gemini 2.5 Pro (Multimodal)' },
    { id: 'gemini-2.5-flash-native-audio-preview-09-2025', name: 'Gemini 2.5 Flash (Multimedia Speed)' }
];

const QWEN_MODELS = [
    { id: 'thesby/Qwen3-VL-8B-NSFW-Caption-V4.5', name: 'Thesby Qwen 3 VL 8B NSFW Caption V4.5' },
    { id: 'huihui-ai/Huihui-Qwen3-VL-8B-Instruct-abliterated', name: 'Huihui Qwen 3 VL 8B Abliterated (Uncensored)' },
    { id: 'Qwen/Qwen3-VL-8B-Instruct-FP8', name: 'Qwen 3 VL 8B FP8' },
];

const DEFAULT_BULK_INSTRUCTIONS = `Dont use ambiguous language "perhaps" for example. Describe EVERYTHING visible: characters, clothing, actions, background, objects, lighting, and camera angle. Refrain from using generic phrases like "character, male, figure of" and use specific terminology: "woman, girl, boy, man". Do not mention the art style.`;
const DEFAULT_REFINEMENT_INSTRUCTIONS = `Refine the caption to be more descriptive and cinematic. Ensure all colors and materials are mentioned.`;

const App: React.FC = () => {
  // --- STATE ---
  const [mediaFiles, setMediaFiles] = useState<MediaFile[]>([]);
  const [triggerWord, setTriggerWord] = useState<string>('MyStyle');
  const [apiProvider, setApiProvider] = useState<ApiProvider>('gemini');
  const [geminiApiKey, setGeminiApiKey] = useState<string>(process.env.API_KEY || '');
  const [geminiModel, setGeminiModel] = useState<string>(GEMINI_MODELS[0].id);
  const [hasSelectedKey, setHasSelectedKey] = useState<boolean>(false);

  // Qwen Options
  const [qwenEndpoint, setQwenEndpoint] = useState<string>('');
  const [useCustomQwenModel, setUseCustomQwenModel] = useState<boolean>(false);
  const [customQwenModelId, setCustomQwenModelId] = useState<string>('');
  const [qwenModel, setQwenModel] = useState<string>(QWEN_MODELS[0].id);
  const [qwenOsType, setQwenOsType] = useState<OSType>(() => navigator.userAgent.includes("Windows") ? 'windows' : 'linux');
  const [qwenInstallDir, setQwenInstallDir] = useState<string>(() => navigator.userAgent.includes("Windows") ? 'C:\\AI\\qwen_local' : '/home/user/ai/qwen_local');
  const [qwenMaxTokens, setQwenMaxTokens] = useState<number>(8192);
  const [qwen8Bit, setQwen8Bit] = useState<boolean>(false);
  const [qwenEager, setQwenEager] = useState<boolean>(false);
  const [qwenVideoFrameCount, setQwenVideoFrameCount] = useState<number>(8);
  
  // Offline Local Snapshot Options
  const [useOfflineSnapshot, setUseOfflineSnapshot] = useState<boolean>(false);
  const [snapshotPath, setSnapshotPath] = useState<string>('');
  const [virtualModelName, setVirtualModelName] = useState<string>('thesby/Qwen3-VL-8B-NSFW-Caption-V4.5');

  // ComfyUI Options
  const [isComfyEnabled, setIsComfyEnabled] = useState<boolean>(false);
  const [comfyUrl, setComfyUrl] = useState<string>('http://localhost:5000');
  const [comfyWorkflow, setComfyWorkflow] = useState<any>(DEFAULT_COMFY_WORKFLOW);
  const [comfyWorkflowName, setComfyWorkflowName] = useState<string>('Default Workflow');
  const [comfySeed, setComfySeed] = useState<number>(-1);
  const [comfySteps, setComfySteps] = useState<number>(4);
  const [activePreviewId, setActivePreviewId] = useState<string | null>(null);

  // Secure Bridge Options
  const [useSecureBridge, setUseSecureBridge] = useState<boolean>(false);
  const [isFirstTimeBridge, setIsFirstTimeBridge] = useState<boolean>(false);
  const [bridgeOsType, setBridgeOsType] = useState<OSType>(() => navigator.userAgent.includes("Windows") ? 'windows' : 'linux');
  const [bridgeInstallPath, setBridgeInstallPath] = useState<string>('/mnt/Goon/captioner');

  // Queue and Performance
  const [useRequestQueue, setUseRequestQueue] = useState<boolean>(true);
  const [concurrentTasks, setConcurrentTasks] = useState<number>(1);
  const [isQueueRunning, setIsQueueRunning] = useState<boolean>(false);

  // Dataset / Instructions
  const [bulkGenerationInstructions, setBulkGenerationInstructions] = useState<string>(DEFAULT_BULK_INSTRUCTIONS);
  const [bulkRefinementInstructions, setBulkRefinementInstructions] = useState<string>(DEFAULT_REFINEMENT_INSTRUCTIONS);
  const [autofitTextareas, setAutofitTextareas] = useState<boolean>(false);
  const [showSideBySidePreview, setShowSideBySidePreview] = useState<boolean>(false);
  const [datasetPrefix, setDatasetPrefix] = useState<string>('item');
  const [isCharacterTaggingEnabled, setIsCharacterTaggingEnabled] = useState<boolean>(false);
  const [characterShowName, setCharacterShowName] = useState<string>('');
  const [isExporting, setIsExporting] = useState<boolean>(false);

  const abortControllerRef = useRef<AbortController>(new AbortController());

  // --- EFFECTS ---
  useEffect(() => {
    if (window.aistudio) {
        window.aistudio.hasSelectedApiKey().then(setHasSelectedKey);
    }
    const isHttps = window.location.protocol === 'https:';
    if (!qwenEndpoint) {
        setQwenEndpoint(isHttps ? '' : 'http://localhost:8000/v1');
    }
  }, [qwenEndpoint]);

  // Handle Modal Keyboard Navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (!activePreviewId) return;
      if (e.key === 'ArrowRight') handleNextPreview();
      if (e.key === 'ArrowLeft') handlePrevPreview();
      if (e.key === 'Escape') setActivePreviewId(null);
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [activePreviewId, mediaFiles]);

  // --- MEMOIZED VALUES ---
  const hasValidConfig = useMemo(() => {
    if (apiProvider === 'gemini') return !!geminiApiKey;
    return qwenEndpoint !== '';
  }, [apiProvider, geminiApiKey, qwenEndpoint]);

  const selectedFiles = useMemo(() => {
    return (mediaFiles || []).filter(mf => mf.isSelected);
  }, [mediaFiles]);
  const currentPreviewItem = useMemo(() => (mediaFiles || []).find(m => m.id === activePreviewId), [mediaFiles, activePreviewId]);

  const qwenEffectiveModel = useMemo(() => {
    if (useOfflineSnapshot) return virtualModelName;
    return useCustomQwenModel ? customQwenModelId : qwenModel;
  }, [useOfflineSnapshot, virtualModelName, useCustomQwenModel, customQwenModelId, qwenModel]);

  const qwenStartCommand = useMemo(() => {
    const isWin = qwenOsType === 'windows';
    const path = qwenInstallDir.replace(/[\\/]+$/, '');
    
    // Model logic for command
    const modelToLoad = useOfflineSnapshot ? snapshotPath : (useCustomQwenModel ? customQwenModelId : qwenModel);
    
    const activate = isWin ? `venv\\Scripts\\activate` : `source venv/bin/activate`;
    const python = isWin ? `python` : `python3`;
    const offlineEnv = isWin ? `set HF_HUB_OFFLINE=1` : `export HF_HUB_OFFLINE=1`;
    
    let args = `--model "${modelToLoad}" --max-model-len ${qwenMaxTokens}`;
    if (useOfflineSnapshot) {
      args += ` --served-model-name "${virtualModelName}"`;
    }
    if (qwen8Bit) args += ` --load-format bitsandbytes --quantization bitsandbytes`;
    if (qwenEager) args += ` --enforce-eager`;
    
    const baseCmd = isWin 
      ? `cd /d "${path}" && ${useOfflineSnapshot ? `${offlineEnv} && ` : ''}${activate} && ${python} -m vllm.entrypoints.openai.api_server ${args}`
      : `cd "${path}" && ${useOfflineSnapshot ? `${offlineEnv} && ` : ''}${activate} && ${python} -m vllm.entrypoints.openai.api_server ${args}`;
    
    return baseCmd;
  }, [qwenOsType, qwenInstallDir, useCustomQwenModel, customQwenModelId, qwenModel, qwenMaxTokens, qwen8Bit, qwenEager, useOfflineSnapshot, snapshotPath, virtualModelName]);

  const bridgeStartCommand = useMemo(() => {
    const isWindows = bridgeOsType === 'windows';
    const path = bridgeInstallPath.replace(/[\\/]+$/, '');
    const activateCmd = isWindows ? `call venv\\Scripts\\activate` : `source venv/bin/activate`;
    const pipCmd = `pip install flask flask-cors requests`;
    const setupCmd = isWindows 
      ? `python -m venv venv && ${activateCmd} && ${pipCmd}`
      : `python3 -m venv venv && ${activateCmd} && ${pipCmd}`;
    return isWindows 
        ? `cd /d "${path}" && ${isFirstTimeBridge ? `${setupCmd} && ` : ''}${activateCmd} && python bridge.py`
        : `cd "${path}" && ${isFirstTimeBridge ? `${setupCmd} && ` : ''}${activateCmd} && python3 bridge.py`;
  }, [bridgeInstallPath, bridgeOsType, isFirstTimeBridge]);

  const isTunnelRequired = useMemo(() => {
    return window.location.protocol === 'https:' && (qwenEndpoint.includes('localhost') || qwenEndpoint.includes('127.0.0.1'));
  }, [qwenEndpoint]);

  // --- HANDLERS ---
  const handleSelectApiKey = async () => {
    if (window.aistudio) {
      await window.aistudio.openSelectKey();
      setHasSelectedKey(true);
    }
  };

  const updateFile = useCallback((id: string, updates: Partial<MediaFile>) => {
    setMediaFiles(prev => (prev || []).map(mf => (mf.id === id ? { ...mf, ...updates } : mf)));
  }, []);

  const handleFilesAdded = useCallback(async (files: File[]) => {
    const mediaUploads = files.filter(file => file.type.startsWith('image/') || file.type.startsWith('video/'));
    const newMediaFiles = await Promise.all(mediaUploads.map(async (file) => ({
      id: `${file.name}-${Math.random()}`,
      file,
      previewUrl: URL.createObjectURL(file),
      caption: '',
      status: GenerationStatus.IDLE,
      isSelected: false,
      customInstructions: '',
      comfyStatus: 'idle'
    } as MediaFile)));
    setMediaFiles(prev => [...(prev || []), ...newMediaFiles]);
  }, []);

  const handleCheckQuality = useCallback(async (id: string) => {
    const fileToProcess = (mediaFiles || []).find(mf => mf.id === id);
    if (!hasValidConfig || !fileToProcess || !fileToProcess.caption) return;

    updateFile(id, { status: GenerationStatus.CHECKING, errorMessage: undefined });

    try {
        const score = apiProvider === 'gemini'
            ? await checkCaptionQuality(fileToProcess.file, fileToProcess.caption, abortControllerRef.current.signal, geminiApiKey, geminiModel)
            : await checkQualityQwen('', qwenEndpoint, qwenEffectiveModel, fileToProcess.file, fileToProcess.caption, qwenVideoFrameCount, abortControllerRef.current.signal);
        
        updateFile(id, { qualityScore: score, status: GenerationStatus.SUCCESS });
    } catch (err: any) {
        if (err.name === 'AbortError' || err.message === 'AbortError') {
            updateFile(id, { status: GenerationStatus.IDLE, errorMessage: "Stopped by user" });
        } else {
            updateFile(id, { status: GenerationStatus.ERROR, errorMessage: err.message });
        }
    }
  }, [mediaFiles, apiProvider, qwenEndpoint, qwenEffectiveModel, qwenVideoFrameCount, hasValidConfig, updateFile, geminiApiKey, geminiModel]);

  const handleGenerateCaption = useCallback(async (id: string, itemInstructions?: string) => {
    const fileToProcess = (mediaFiles || []).find(mf => mf.id === id);
    if (!hasValidConfig || !fileToProcess) return;

    updateFile(id, { status: GenerationStatus.GENERATING, errorMessage: undefined, qualityScore: undefined });
    
    const combinedInstructions = `${bulkGenerationInstructions}\n\n${itemInstructions || ''}`.trim();

    try {
      const caption = apiProvider === 'gemini'
        ? await generateCaption(fileToProcess.file, triggerWord, combinedInstructions, isCharacterTaggingEnabled, characterShowName, abortControllerRef.current.signal, geminiApiKey, geminiModel)
        : await generateCaptionQwen('', qwenEndpoint, qwenEffectiveModel, fileToProcess.file, triggerWord, combinedInstructions, isCharacterTaggingEnabled, characterShowName, qwenVideoFrameCount, abortControllerRef.current.signal);
      
      updateFile(id, { caption, status: GenerationStatus.SUCCESS });
    } catch (err: any) {
      if (err.name === 'AbortError' || err.message === 'AbortError') {
          updateFile(id, { status: GenerationStatus.IDLE, errorMessage: "Stopped by user" });
      } else {
          updateFile(id, { status: GenerationStatus.ERROR, errorMessage: err.message });
      }
    }
  }, [mediaFiles, triggerWord, apiProvider, qwenEndpoint, qwenEffectiveModel, qwenVideoFrameCount, bulkGenerationInstructions, isCharacterTaggingEnabled, characterShowName, hasValidConfig, updateFile, geminiApiKey, geminiModel]);

  const handleRefineCaptionItem = useCallback(async (id: string, itemInstructions?: string) => {
    const fileToProcess = (mediaFiles || []).find(mf => mf.id === id);
    if (!hasValidConfig || !fileToProcess || !fileToProcess.caption) return;

    updateFile(id, { status: GenerationStatus.GENERATING, errorMessage: undefined });
    
    const combinedInstructions = `${bulkRefinementInstructions}\n\n${itemInstructions || ''}`.trim();

    try {
      const caption = apiProvider === 'gemini'
        ? await refineCaption(fileToProcess.file, fileToProcess.caption, combinedInstructions, abortControllerRef.current.signal, geminiApiKey, geminiModel)
        : await refineCaptionQwen('', qwenEndpoint, qwenEffectiveModel, fileToProcess.file, fileToProcess.caption, combinedInstructions, qwenVideoFrameCount, abortControllerRef.current.signal);
      
      updateFile(id, { caption, status: GenerationStatus.SUCCESS });
    } catch (err: any) {
      if (err.name === 'AbortError' || err.message === 'AbortError') {
          updateFile(id, { status: GenerationStatus.IDLE, errorMessage: "Stopped by user" });
      } else {
          updateFile(id, { status: GenerationStatus.ERROR, errorMessage: err.message });
      }
    }
  }, [mediaFiles, apiProvider, qwenEndpoint, qwenEffectiveModel, qwenVideoFrameCount, bulkRefinementInstructions, hasValidConfig, updateFile, geminiApiKey, geminiModel]);

  // --- QUEUE CONTROLLER ---
  const runTasksInQueue = async (tasks: (() => Promise<void>)[]) => {
    setIsQueueRunning(true);
    const pool = new Set<Promise<void>>();
    for (const task of tasks) {
      if (abortControllerRef.current.signal.aborted) break;
      const promise = task();
      pool.add(promise);
      promise.finally(() => pool.delete(promise));
      if (pool.size >= concurrentTasks) {
        await Promise.race(pool);
      }
    }
    await Promise.all(pool);
    setIsQueueRunning(false);
  };

  const handleBulkGenerate = () => {
    const tasks = selectedFiles.map(file => () => handleGenerateCaption(file.id, file.customInstructions));
    if (useRequestQueue) {
      runTasksInQueue(tasks);
    } else {
      tasks.forEach(t => t());
    }
  };

  const handleBulkRefine = () => {
    const tasks = selectedFiles.map(file => () => handleRefineCaptionItem(file.id, file.customInstructions));
    if (useRequestQueue) {
      runTasksInQueue(tasks);
    } else {
      tasks.forEach(t => t());
    }
  };

  const handleBulkQualityCheck = () => {
    const tasks = selectedFiles.map(file => () => handleCheckQuality(file.id));
    if (useRequestQueue) {
      runTasksInQueue(tasks);
    } else {
      tasks.forEach(t => t());
    }
  };

  const handleClearWorkflow = useCallback(() => {
    setComfyWorkflow(DEFAULT_COMFY_WORKFLOW);
    setComfyWorkflowName('Default Workflow');
  }, []);

  const handleComfyPreview = useCallback(async (id: string) => {
    const item = (mediaFiles || []).find(m => m.id === id);
    if (!item || !comfyWorkflow || !comfyUrl) return;

    updateFile(id, { comfyStatus: 'generating', comfyErrorMessage: undefined });
    try {
        const previewUrl = await sendComfyPrompt(comfyUrl, comfyWorkflow, item.caption, comfySeed, comfySteps, useSecureBridge, abortControllerRef.current.signal);
        updateFile(id, { comfyPreviewUrl: previewUrl, comfyStatus: 'success' });
    } catch (err: any) {
        if (err.name === 'AbortError' || err.message === 'Aborted') {
            updateFile(id, { comfyStatus: 'idle', comfyErrorMessage: "Stopped" });
        } else {
            updateFile(id, { comfyStatus: 'error', comfyErrorMessage: err.message });
        }
    }
  }, [mediaFiles, comfyWorkflow, comfyUrl, comfySeed, comfySteps, useSecureBridge, updateFile]);

  const handleBulkPreview = () => {
    selectedFiles.forEach(file => handleComfyPreview(file.id));
  };

  const handleDeleteSelected = useCallback(() => {
    setMediaFiles(prev => {
      const remaining = (prev || []).filter(mf => !mf.isSelected);
      return remaining || [];
    });
  }, []);

  const handleStopTasks = () => {
    abortControllerRef.current.abort();
    abortControllerRef.current = new AbortController();
    setIsQueueRunning(false);
    setMediaFiles(prev => (prev || []).map(mf => {
      if (mf.status === GenerationStatus.GENERATING || mf.status === GenerationStatus.CHECKING) {
        return { ...mf, status: GenerationStatus.IDLE, errorMessage: "Stopped by user" };
      }
      if (mf.comfyStatus === 'generating') {
        return { ...mf, comfyStatus: 'idle', comfyErrorMessage: "Stopped" };
      }
      return mf;
    }));
  };

  const handleExportDataset = useCallback(async () => {
    if (selectedFiles.length === 0) return;
    const JSZip = (window as any).JSZip;
    if (!JSZip) return alert("JSZip not loaded.");

    setIsExporting(true);
    try {
      const zip = new JSZip();
      const prefix = datasetPrefix.trim() || 'item';
      selectedFiles.forEach((mf, idx) => {
        const fileExt = mf.file.name.split('.').pop() || 'dat';
        const finalName = `${prefix}_${idx + 1}`;
        zip.file(`${finalName}.${fileExt}`, mf.file);
        zip.file(`${finalName}.txt`, mf.caption || "");
      });
      const content = await zip.generateAsync({ type: 'blob' });
      const link = document.createElement('a');
      link.href = URL.createObjectURL(content);
      link.download = `lora_dataset_${new Date().getTime()}.zip`;
      link.click();
    } catch (err: any) {
        alert("Export failed: " + err.message);
    } finally { setIsExporting(false); }
  }, [selectedFiles, datasetPrefix]);

  const handleNextPreview = useCallback(() => {
    if (!activePreviewId || (mediaFiles || []).length <= 1) return;
    const currentIndex = mediaFiles.findIndex(m => m.id === activePreviewId);
    const nextIndex = (currentIndex + 1) % mediaFiles.length;
    setActivePreviewId(mediaFiles[nextIndex].id);
  }, [activePreviewId, mediaFiles]);

  const handlePrevPreview = useCallback(() => {
    if (!activePreviewId || (mediaFiles || []).length <= 1) return;
    const currentIndex = mediaFiles.findIndex(m => m.id === activePreviewId);
    const prevIndex = (currentIndex - 1 + mediaFiles.length) % mediaFiles.length;
    setActivePreviewId(mediaFiles[prevIndex].id);
  }, [activePreviewId, mediaFiles]);

  const downloadQwenSetupScript = () => {
    const isWin = qwenOsType === 'windows';
    const content = isWin 
      ? `@echo off\npython -m venv venv\ncall venv\\Scripts\\activate\npip install vllm bitsandbytes\necho Setup Complete.`
      : `#!/bin/bash\npython3 -m venv venv\nsource venv/bin/activate\npip install vllm bitsandbytes\necho Setup Complete.`;
    const filename = isWin ? 'setup_qwen.bat' : 'setup_qwen.sh';
    const blob = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  };

  const downloadBridgeScript = () => {
    const code = `import requests\nfrom flask import Flask, request, Response\nfrom flask_cors import CORS\napp = Flask(__name__)\nCORS(app)\nTARGET = "http://127.0.0.1:8188"\n@app.route('/', defaults={'path': ''}, methods=['GET','POST','PUT','DELETE','PATCH','OPTIONS'])\n@app.route('/<path:path>', methods=['GET','POST','PUT','DELETE','PATCH','OPTIONS'])\ndef proxy(path):\n  url = f"{TARGET}/{path}"\n  headers = {k:v for k,v in request.headers.items() if k.lower() not in ['host', 'origin', 'referer']}\n  resp = requests.request(method=request.method, url=url, headers=headers, data=request.get_data(), params=request.args, stream=True)\n  return Response(resp.content, resp.status_code, [(n,v) for n,v in resp.headers.items() if n.lower() not in ['content-encoding','content-length','transfer-encoding','connection']])\nif __name__ == '__main__': app.run(port=5000, host='0.0.0.0')`;
    const blob = new Blob([code], { type: 'text/x-python' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'bridge.py';
    a.click();
    URL.revokeObjectURL(url);
  };

  // --- RENDER ---
  return (
    <div className="min-h-screen bg-gray-950 text-gray-100 font-sans p-4 sm:p-8">
      {/* PREVIEW MODAL */}
      {activePreviewId && currentPreviewItem && (
          <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/95 backdrop-blur-sm animate-fade-in" onClick={() => setActivePreviewId(null)}>
              <div className="bg-gray-900 w-full max-w-6xl rounded-2xl border border-gray-700 overflow-hidden flex flex-col max-h-[95vh] animate-scale-up shadow-2xl relative" onClick={(e) => e.stopPropagation()}>
                  <button onClick={handlePrevPreview} className="absolute left-4 top-1/2 -translate-y-1/2 z-10 p-4 bg-gray-800/80 hover:bg-indigo-600 rounded-full text-white shadow-2xl transition-all border border-white/5 active:scale-90">
                    <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M15 19l-7-7 7-7"/></svg>
                  </button>
                  <button onClick={handleNextPreview} className="absolute right-4 top-1/2 -translate-y-1/2 z-10 p-4 bg-gray-800/80 hover:bg-indigo-600 rounded-full text-white shadow-2xl transition-all border border-white/5 active:scale-90">
                    <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M9 5l7 7-7 7"/></svg>
                  </button>
                  <div className="px-6 py-4 border-b border-gray-800 flex justify-between items-center bg-gray-850">
                      <div className="flex items-center gap-4">
                        <SparklesIcon className="w-5 h-5 text-indigo-400" />
                        <div className="flex flex-col">
                            <h3 className="text-xs font-black uppercase tracking-widest text-gray-400">{(mediaFiles || []).findIndex(m => m.id === activePreviewId) + 1} of {mediaFiles.length}</h3>
                            <h3 className="text-[11px] font-bold truncate max-w-md text-gray-500">{currentPreviewItem.file.name}</h3>
                        </div>
                      </div>
                      <div className="flex items-center gap-2">
                        <button onClick={handlePrevPreview} className="px-4 py-2 bg-gray-800 hover:bg-gray-700 rounded-xl text-[10px] font-black uppercase transition-all">Prev</button>
                        <button onClick={handleNextPreview} className="px-4 py-2 bg-gray-800 hover:bg-gray-700 rounded-xl text-[10px] font-black uppercase transition-all">Next</button>
                        <button onClick={() => setActivePreviewId(null)} className="ml-4 p-2 hover:bg-red-600/20 rounded-full transition-colors text-gray-500 hover:text-red-400"><XIcon className="w-5 h-5" /></button>
                      </div>
                  </div>
                  <div className="flex-grow overflow-y-auto p-6 space-y-8 bg-black/40">
                      <div className="grid grid-cols-1 md:grid-cols-2 gap-8 h-[450px]">
                          <div className="bg-black rounded-2xl border border-gray-800 flex items-center justify-center overflow-hidden relative shadow-inner">
                             {currentPreviewItem.file.type.startsWith('video/') ? <video src={currentPreviewItem.previewUrl} className="max-h-full" controls /> : <img src={currentPreviewItem.previewUrl} className="max-h-full object-contain" />}
                             <div className="absolute top-3 left-3 bg-black/70 backdrop-blur-md px-3 py-1 rounded-lg text-[10px] font-black uppercase text-white/80 border border-white/5">Original Data</div>
                          </div>
                          <div className="bg-black rounded-2xl border border-gray-800 flex items-center justify-center relative overflow-hidden shadow-inner">
                             {currentPreviewItem.comfyPreviewUrl ? <img src={currentPreviewItem.comfyPreviewUrl} className="max-h-full object-contain" /> : <div className="text-xs uppercase text-gray-700 tracking-widest font-black">No Preview Rendered</div>}
                             {currentPreviewItem.comfyStatus === 'generating' && <div className="absolute inset-0 bg-black/60 flex flex-col items-center justify-center gap-3"><LoaderIcon className="w-10 h-10 animate-spin text-orange-500" /><span className="text-xs font-black uppercase text-orange-400 tracking-widest">Rendering via ComfyUI...</span></div>}
                             <div className="absolute top-3 left-3 bg-orange-600/70 backdrop-blur-md px-3 py-1 rounded-lg text-[10px] font-black uppercase text-white/90 border border-white/5">ComfyUI Render</div>
                          </div>
                      </div>
                      <div className="space-y-6">
                          <textarea value={currentPreviewItem.caption} onChange={(e) => updateFile(currentPreviewItem.id, { caption: e.target.value })} className="w-full bg-gray-950 border border-gray-700 rounded-2xl p-6 text-sm h-40 outline-none focus:ring-2 focus:ring-indigo-500 transition-all shadow-inner leading-relaxed" />
                          <div className="flex gap-4">
                             <input type="text" value={currentPreviewItem.customInstructions} onChange={(e) => updateFile(currentPreviewItem.id, { customInstructions: e.target.value })} placeholder="Refine caption instructions..." className="flex-grow bg-gray-800 border border-gray-700 rounded-xl px-5 py-3 text-sm outline-none focus:ring-1 focus:ring-indigo-500 shadow-sm" />
                             <button onClick={() => handleGenerateCaption(currentPreviewItem.id, currentPreviewItem.customInstructions)} className="px-8 py-3 bg-green-600 hover:bg-green-500 text-white rounded-xl text-xs font-black uppercase transition-all shadow-xl active:scale-95">Re-Generate</button>
                             <button onClick={() => handleRefineCaptionItem(currentPreviewItem.id, currentPreviewItem.customInstructions)} className="px-8 py-3 bg-indigo-600 hover:bg-indigo-500 text-white rounded-xl text-xs font-black uppercase transition-all shadow-xl active:scale-95">Refine</button>
                             <button onClick={() => handleCheckQuality(currentPreviewItem.id)} className="px-8 py-3 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-xs font-black uppercase transition-all shadow-xl active:scale-95">Check Quality</button>
                             <button onClick={() => handleComfyPreview(currentPreviewItem.id)} className="px-8 py-3 bg-orange-600 hover:bg-orange-500 text-white rounded-xl text-xs font-black uppercase transition-all shadow-xl active:scale-95">Preview</button>
                          </div>
                      </div>
                  </div>
              </div>
          </div>
      )}

      <main className="max-w-6xl mx-auto space-y-8 animate-fade-in">
        <section className="bg-gray-900 border border-gray-800 p-8 rounded-3xl shadow-2xl space-y-12">
            <h2 className="text-3xl font-black flex items-center gap-4 uppercase tracking-tighter text-white">1. Global Settings & Actions</h2>
            
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-16">
                <div className="space-y-10">
                    <div>
                        <label className="text-xs font-black text-gray-500 uppercase tracking-widest block mb-4">AI Provider</label>
                        <div className="flex p-1.5 bg-black rounded-2xl border border-gray-800 shadow-inner">
                            <button onClick={() => setApiProvider('gemini')} className={`flex-1 py-3 text-xs font-black uppercase rounded-xl transition-all ${apiProvider === 'gemini' ? 'bg-indigo-600 text-white shadow-lg' : 'text-gray-600 hover:text-gray-400'}`}>Google Gemini</button>
                            <button onClick={() => setApiProvider('qwen')} className={`flex-1 py-3 text-xs font-black uppercase rounded-xl transition-all ${apiProvider === 'qwen' ? 'bg-indigo-600 text-white shadow-lg' : 'text-gray-600 hover:text-gray-400'}`}>Local Qwen (GPU)</button>
                        </div>
                    </div>

                    {apiProvider === 'gemini' ? (
                        <div className="bg-indigo-500/5 border border-indigo-500/20 p-6 rounded-3xl space-y-6 animate-slide-down shadow-xl">
                            <div className="space-y-4">
                                <div className="flex justify-between items-center">
                                    <label className="text-[10px] font-black text-indigo-400 uppercase tracking-widest">Gemini Model Version</label>
                                </div>
                                <select 
                                    value={geminiModel} 
                                    onChange={(e) => setGeminiModel(e.target.value)}
                                    className="w-full p-3 bg-black border border-indigo-500/30 rounded-xl text-xs font-bold text-gray-300 shadow-inner focus:ring-1 focus:ring-indigo-500 outline-none"
                                >
                                    {GEMINI_MODELS.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
                                </select>
                            </div>

                            <div className="space-y-4">
                                <div className="flex justify-between items-center">
                                    <label className="text-[10px] font-black text-indigo-400 uppercase tracking-widest">Gemini API Key</label>
                                    {geminiApiKey && <span className="flex items-center gap-1.5 text-[9px] font-black uppercase text-green-400 bg-green-400/10 px-2 py-0.5 rounded-full"><CheckCircleIcon className="w-3 h-3"/> Configured</span>}
                                </div>
                                <div className="relative group">
                                    <input 
                                        type="password" 
                                        value={geminiApiKey} 
                                        onChange={(e) => setGeminiApiKey(e.target.value)}
                                        placeholder="Enter your Gemini API key here..."
                                        className="w-full py-4 px-5 bg-black border border-indigo-500/30 rounded-2xl text-xs font-mono shadow-inner focus:ring-1 focus:ring-indigo-500 outline-none hover:border-indigo-500/60 transition-all"
                                    />
                                    <div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none text-indigo-400/50 group-hover:text-indigo-400 transition-colors">
                                        <SparklesIcon className="w-5 h-5" />
                                    </div>
                                </div>
                            </div>
                            <p className="text-[10px] text-gray-500 flex items-center gap-1.5 px-1">
                                <AlertTriangleIcon className="w-3 h-3 text-indigo-400" />
                                Get an API key from 
                                <a href="https://aistudio.google.com/app/apikey" target="_blank" rel="noopener noreferrer" className="text-indigo-400 hover:underline font-bold">Google AI Studio</a>
                            </p>
                        </div>
                    ) : (
                        <div className="bg-gray-950 p-6 rounded-3xl border border-gray-800 space-y-6 animate-slide-down shadow-xl">
                            <div className="flex justify-between items-center mb-2">
                                <label className="text-[10px] font-black text-indigo-400 uppercase tracking-widest">Local Model Configuration</label>
                                <div className="flex items-center gap-4">
                                  <label className="flex items-center gap-2 cursor-pointer group">
                                      <input type="checkbox" checked={useOfflineSnapshot} onChange={e => setUseOfflineSnapshot(e.target.checked)} className="h-4 w-4 rounded bg-gray-800 border-gray-700 text-indigo-600" />
                                      <span className="text-[10px] font-bold text-orange-400 group-hover:text-orange-300">Use Offline Local Snapshot</span>
                                  </label>
                                  {!useOfflineSnapshot && (
                                    <label className="flex items-center gap-2 cursor-pointer group">
                                        <input type="checkbox" checked={useCustomQwenModel} onChange={e => setUseCustomQwenModel(e.target.checked)} className="h-4 w-4 rounded bg-gray-800 border-gray-700 text-indigo-600" />
                                        <span className="text-[10px] font-bold text-gray-500 group-hover:text-gray-300">Custom Model ID</span>
                                    </label>
                                  )}
                                </div>
                            </div>
                            
                            {useOfflineSnapshot ? (
                              <div className="space-y-4 animate-slide-down">
                                <div className="space-y-1">
                                    <label className="text-[9px] font-black text-gray-700 uppercase">Snapshot Directory Path</label>
                                    <input type="text" value={snapshotPath} onChange={e => setSnapshotPath(e.target.value)} placeholder="/path/to/hf_cache/.../snapshots/hash..." className="w-full p-2.5 bg-black border border-gray-800 rounded-xl text-xs font-mono shadow-inner" />
                                </div>
                                <div className="space-y-1">
                                    <label className="text-[9px] font-black text-gray-700 uppercase">Virtual Model Name (Served Name)</label>
                                    <input type="text" value={virtualModelName} onChange={e => setVirtualModelName(e.target.value)} placeholder="org/model-id..." className="w-full p-2.5 bg-black border border-gray-800 rounded-xl text-xs font-mono shadow-inner" />
                                </div>
                              </div>
                            ) : useCustomQwenModel ? (
                                <input type="text" value={customQwenModelId} onChange={e => setCustomQwenModelId(e.target.value)} placeholder="org/model-id..." className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs font-mono shadow-inner" />
                            ) : (
                                <select value={qwenModel} onChange={e => setQwenModel(e.target.value)} className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs font-bold text-gray-300 shadow-inner">
                                    {QWEN_MODELS.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
                                </select>
                            )}

                            <div className="pt-4 border-t border-gray-800 space-y-4">
                                <div className="flex justify-between items-center">
                                    <span className="text-[10px] font-black text-gray-600 uppercase">OS Type:</span>
                                    <div className="flex gap-2">
                                        <button onClick={() => setQwenOsType('windows')} className={`px-3 py-1 text-[9px] font-black uppercase rounded-lg transition-all ${qwenOsType === 'windows' ? 'bg-indigo-600 text-white' : 'text-gray-600 hover:text-gray-400'}`}>Windows</button>
                                        <button onClick={() => setQwenOsType('linux')} className={`px-3 py-1 text-[9px] font-black uppercase rounded-lg transition-all ${qwenOsType === 'linux' ? 'bg-indigo-600 text-white' : 'text-gray-600 hover:text-gray-400'}`}>Linux</button>
                                    </div>
                                </div>
                                
                                <div className="grid grid-cols-4 gap-4">
                                    <div className="col-span-3 space-y-1">
                                        <label className="text-[9px] font-black text-gray-700 uppercase">Install Path</label>
                                        <input type="text" value={qwenInstallDir} onChange={e => setQwenInstallDir(e.target.value)} className="w-full p-2.5 bg-black border border-gray-800 rounded-xl text-xs font-mono" />
                                    </div>
                                    <div className="space-y-1">
                                        <label className="text-[9px] font-black text-gray-700 uppercase">Max Tokens</label>
                                        <input type="number" value={qwenMaxTokens} onChange={e => setQwenMaxTokens(Number(e.target.value))} className="w-full p-2.5 bg-black border border-gray-800 rounded-xl text-xs text-center" />
                                    </div>
                                </div>

                                <div className="flex flex-col gap-2">
                                    <label className="flex items-center gap-2 cursor-pointer group">
                                        <input type="checkbox" checked={qwen8Bit} onChange={e => setQwen8Bit(e.target.checked)} className="h-4 w-4 rounded bg-gray-800 text-indigo-600" />
                                        <span className="text-[10px] font-bold text-gray-500 group-hover:text-gray-300">Enable 8-bit Quantization (bitsandbytes)</span>
                                    </label>
                                    <label className="flex items-center gap-2 cursor-pointer group">
                                        <input type="checkbox" checked={qwenEager} onChange={e => setQwenEager(e.target.checked)} className="h-4 w-4 rounded bg-gray-950 text-indigo-600" />
                                        <span className="text-[10px] font-bold text-gray-500 group-hover:text-gray-300">Enforce Eager Mode</span>
                                    </label>
                                </div>

                                <button onClick={downloadQwenSetupScript} className="w-full py-3 bg-green-700 hover:bg-green-600 text-white text-[10px] font-black uppercase rounded-xl transition-all shadow-lg">Download Setup Script</button>

                                <div className="space-y-2">
                                    <label className="text-[9px] font-black text-gray-700 uppercase">Local Start Command:</label>
                                    <div className="relative group">
                                        <div className="p-3 bg-black rounded-xl border border-gray-900 font-mono text-[10px] text-green-500/80 break-all leading-relaxed max-h-24 overflow-y-auto shadow-inner">
                                            {qwenStartCommand}
                                        </div>
                                        <button onClick={() => navigator.clipboard.writeText(qwenStartCommand)} className="absolute top-2 right-2 p-1.5 bg-gray-800 hover:bg-gray-700 text-gray-400 rounded-lg opacity-0 group-hover:opacity-100 transition-all"><CopyIcon className="w-3.5 h-3.5"/></button>
                                    </div>
                                </div>
                                
                                <div className="space-y-1">
                                    <label className="text-[10px] font-black text-indigo-400 uppercase tracking-widest">Endpoint URL (Tunnel or Local)</label>
                                    <input type="text" value={qwenEndpoint} onChange={e => setQwenEndpoint(e.target.value)} placeholder="http://localhost:8000/v1" className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs font-mono shadow-inner focus:ring-1 focus:ring-indigo-500 outline-none" />
                                </div>
                            </div>
                        </div>
                    )}

                    <div className="space-y-6">
                        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                            <div className="space-y-2">
                                <label className="text-[10px] font-black text-gray-500 uppercase tracking-widest">Trigger Word</label>
                                <input type="text" value={triggerWord} onChange={e => setTriggerWord(e.target.value)} className="w-full p-3 bg-gray-950 border border-gray-800 rounded-2xl text-sm font-bold shadow-inner" placeholder="MyStyle" />
                            </div>
                            <div className="space-y-2">
                                <label className="text-[10px] font-black text-gray-500 uppercase tracking-widest">File Prefix</label>
                                <input type="text" value={datasetPrefix} onChange={e => setDatasetPrefix(e.target.value)} className="w-full p-3 bg-gray-950 border border-gray-800 rounded-2xl text-sm font-bold shadow-inner" placeholder="item" />
                            </div>
                        </div>
                        <div className="bg-gray-800/40 p-5 rounded-3xl border border-gray-800 space-y-4 shadow-xl">
                            <label className="flex items-center gap-3 cursor-pointer group">
                                <input type="checkbox" checked={isCharacterTaggingEnabled} onChange={(e) => setIsCharacterTaggingEnabled(e.target.checked)} className="h-6 w-6 rounded-lg bg-gray-900 border-gray-700 text-indigo-600 transition-all shadow-sm" />
                                <span className="text-xs font-black text-gray-500 uppercase tracking-wider group-hover:text-gray-300 transition-colors">Character Tagging</span>
                            </label>
                            {isCharacterTaggingEnabled && (
                                <div className="animate-slide-down">
                                    <input type="text" value={characterShowName} onChange={(e) => setCharacterShowName(e.target.value)} placeholder="Enter show/series name..." className="w-full p-3 bg-gray-950 border border-gray-700 rounded-xl text-xs font-medium focus:ring-1 focus:ring-indigo-500 outline-none transition-all shadow-inner" />
                                </div>
                            )}
                        </div>
                    </div>
                </div>

                <div className="space-y-10">
                    <div className="space-y-8">
                        <div className="space-y-3">
                            <label className="text-xs font-black text-gray-500 uppercase tracking-widest block">System Instructions & Prompting</label>
                            <textarea value={bulkGenerationInstructions} onChange={(e) => setBulkGenerationInstructions(e.target.value)} className="w-full p-5 bg-gray-950 border border-gray-800 rounded-3xl text-[13px] h-40 leading-relaxed resize-none outline-none focus:ring-2 focus:ring-indigo-500 shadow-inner" placeholder="Enter global captioning rules..." />
                        </div>
                        <div className="space-y-3">
                            <label className="text-xs font-black text-indigo-400 uppercase tracking-widest block">Refinement Instructions</label>
                            <textarea value={bulkRefinementInstructions} onChange={(e) => setBulkRefinementInstructions(e.target.value)} className="w-full p-5 bg-gray-950 border border-indigo-500/20 rounded-3xl text-[13px] h-40 leading-relaxed resize-none outline-none focus:ring-2 focus:ring-indigo-500 shadow-inner" placeholder="Enter instructions for refining existing captions..." />
                        </div>
                    </div>

                    <div className="flex flex-col gap-6 pt-4 border-t border-gray-800">
                        <div className="flex flex-wrap gap-x-8 gap-y-4">
                            <label className="flex items-center gap-3 cursor-pointer group">
                                <input type="checkbox" checked={autofitTextareas} onChange={(e) => setAutofitTextareas(e.target.checked)} className="h-5 w-5 rounded-md bg-gray-900 border-gray-700 text-indigo-500 shadow-inner" />
                                <span className="text-xs font-bold text-gray-500 uppercase group-hover:text-gray-300 transition-colors">Autofit Textboxes</span>
                            </label>
                            <label className="flex items-center gap-3 cursor-pointer group">
                                <input type="checkbox" checked={showSideBySidePreview} onChange={(e) => setShowSideBySidePreview(e.target.checked)} className="h-5 w-5 rounded-md bg-gray-900 border-gray-700 text-indigo-500 shadow-inner" />
                                <span className="text-xs font-bold text-gray-500 uppercase group-hover:text-gray-300 transition-colors">Side-by-Side Comparison</span>
                            </label>
                            <label className="flex items-center gap-3 cursor-pointer group">
                                <input type="checkbox" checked={isComfyEnabled} onChange={(e) => setIsComfyEnabled(e.target.checked)} className="h-5 w-5 rounded-md bg-gray-900 border-gray-700 text-orange-500 shadow-inner" />
                                <span className="text-xs font-black text-orange-500 uppercase tracking-widest group-hover:text-orange-400 transition-colors">Enable ComfyUI Previews</span>
                            </label>
                        </div>
                        
                        <div className="bg-indigo-600/5 border border-indigo-600/20 p-6 rounded-3xl space-y-4">
                            <div className="flex justify-between items-center">
                                <label className="flex items-center gap-3 cursor-pointer group">
                                    <input type="checkbox" checked={useRequestQueue} onChange={(e) => setUseRequestQueue(e.target.checked)} className="h-5 w-5 rounded bg-gray-900 border-gray-700 text-indigo-500" />
                                    <span className="text-xs font-black text-indigo-400 uppercase tracking-widest group-hover:text-indigo-300 transition-colors">Enable Request Queue</span>
                                </label>
                                {useRequestQueue && (
                                    <div className="flex items-center gap-3">
                                        <label className="text-[10px] font-black text-gray-600 uppercase">Concurrent Tasks</label>
                                        <input type="number" min="1" max="10" value={concurrentTasks} onChange={(e) => setConcurrentTasks(Number(e.target.value))} className="w-16 p-1 bg-black border border-gray-800 rounded text-center text-xs font-bold" />
                                    </div>
                                )}
                            </div>
                            <p className="text-[10px] text-gray-600 italic">Recommended for Gemini Free Tier or Local GPU to prevent rate limits or OOM errors.</p>
                        </div>

                        {isComfyEnabled && (
                            <div className="bg-orange-600/5 border border-orange-600/20 p-6 rounded-3xl space-y-6 animate-slide-down shadow-xl">
                                <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
                                    <div className="space-y-2">
                                        <label className="text-[10px] font-black text-gray-600 uppercase">Endpoint</label>
                                        <input type="text" value={comfyUrl} onChange={(e) => setComfyUrl(e.target.value)} placeholder="http://127.0.0.1:8188" className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs font-mono shadow-inner" />
                                    </div>
                                    <div className="space-y-2">
                                        <label className="text-[10px] font-black text-gray-600 uppercase">Workflow ({comfyWorkflowName})</label>
                                        <div className="flex gap-2">
                                            <button onClick={() => document.getElementById('wf-up')?.click()} className="flex-1 py-2.5 bg-orange-600 hover:bg-orange-500 text-white rounded-xl shadow-lg transition-all active:scale-95 text-[10px] font-black uppercase tracking-widest">Load JSON</button>
                                            <button onClick={handleClearWorkflow} className="px-4 bg-gray-800 hover:bg-gray-700 text-gray-400 rounded-xl transition-all active:scale-95"><TrashIcon className="w-4 h-4"/></button>
                                            <input id="wf-up" type="file" accept=".json" onChange={(e) => {
                                                const f = e.target.files?.[0];
                                                if (f) {
                                                    const r = new FileReader();
                                                    r.onload = (ev) => {
                                                        try {
                                                            setComfyWorkflow(JSON.parse(ev.target?.result as string));
                                                            setComfyWorkflowName(f.name);
                                                        } catch { alert("Invalid Workflow JSON"); }
                                                    };
                                                    r.readAsText(f);
                                                }
                                            }} className="hidden" />
                                        </div>
                                    </div>
                                    <div className="space-y-2">
                                        <label className="text-[10px] font-black text-gray-600 uppercase">Default Seed (-1 for random)</label>
                                        <input type="number" value={comfySeed} onChange={(e) => setComfySeed(Number(e.target.value))} className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs shadow-inner" />
                                    </div>
                                    <div className="space-y-2">
                                        <label className="text-[10px] font-black text-gray-600 uppercase">Steps</label>
                                        <input type="number" value={comfySteps} onChange={(e) => setComfySteps(Number(e.target.value))} className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs shadow-inner" />
                                    </div>
                                </div>

                                {/* Secure Bridge Sub-section */}
                                <div className="pt-6 border-t border-orange-600/10 space-y-6">
                                    <div className="flex justify-between items-center">
                                        <h3 className="text-[11px] font-black text-orange-400 uppercase tracking-widest">Secure Bridge (for HTTPS/Remote access)</h3>
                                        <label className="flex items-center gap-3 cursor-pointer group">
                                            <input type="checkbox" checked={useSecureBridge} onChange={(e) => setUseSecureBridge(e.target.checked)} className="h-5 w-5 rounded bg-gray-900 border-gray-700 text-orange-500" />
                                            <span className="text-[10px] font-bold text-gray-500 group-hover:text-gray-300 transition-colors">Enable Bridge Proxy</span>
                                        </label>
                                    </div>

                                    {useSecureBridge && (
                                        <div className="space-y-6 animate-slide-down">
                                            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
                                                <div className="space-y-2">
                                                    <label className="text-[9px] font-black text-gray-600 uppercase">Bridge OS</label>
                                                    <div className="flex gap-2">
                                                        <button onClick={() => setBridgeOsType('windows')} className={`flex-1 py-2 text-[10px] font-black uppercase rounded-lg transition-all ${bridgeOsType === 'windows' ? 'bg-orange-600 text-white' : 'bg-gray-800 text-gray-500'}`}>Windows</button>
                                                        <button onClick={() => setBridgeOsType('linux')} className={`flex-1 py-2 text-[10px] font-black uppercase rounded-lg transition-all ${bridgeOsType === 'linux' ? 'bg-orange-600 text-white' : 'bg-gray-800 text-gray-500'}`}>Linux</button>
                                                    </div>
                                                </div>
                                                <div className="space-y-2">
                                                    <label className="text-[9px] font-black text-gray-600 uppercase">Install Path</label>
                                                    <input type="text" value={bridgeInstallPath} onChange={(e) => setBridgeInstallPath(e.target.value)} className="w-full p-3 bg-black border border-gray-800 rounded-xl text-xs font-mono shadow-inner" />
                                                </div>
                                            </div>

                                            <div className="space-y-4">
                                                <label className="flex items-center gap-3 cursor-pointer group">
                                                    <input type="checkbox" checked={isFirstTimeBridge} onChange={(e) => setIsFirstTimeBridge(e.target.checked)} className="h-4 w-4 rounded bg-gray-950 border-gray-800 text-orange-500" />
                                                    <span className="text-[10px] font-bold text-gray-500 group-hover:text-gray-300">First-time Setup (Include VENV & Pip Install)</span>
                                                </label>
                                                <div className="flex gap-4">
                                                    <button onClick={downloadBridgeScript} className="flex-1 py-3 bg-orange-700 hover:bg-orange-600 text-white text-[10px] font-black uppercase rounded-xl transition-all shadow-lg">Download Bridge.py</button>
                                                </div>
                                            </div>

                                            <div className="space-y-2">
                                                <label className="text-[9px] font-black text-gray-700 uppercase tracking-widest">Start Command:</label>
                                                <div className="relative group">
                                                    <div className="p-3 bg-black rounded-xl border border-gray-900 font-mono text-[10px] text-green-500/80 break-all leading-relaxed shadow-inner">
                                                        {bridgeStartCommand}
                                                    </div>
                                                    <button onClick={() => navigator.clipboard.writeText(bridgeStartCommand)} className="absolute top-2 right-2 p-1.5 bg-gray-800 hover:bg-gray-700 text-gray-400 rounded-lg opacity-0 group-hover:opacity-100 transition-all"><CopyIcon className="w-3.5 h-3.5"/></button>
                                                </div>
                                                <p className="text-[9px] text-gray-600 italic">The bridge will proxy requests from this HTTPS app to your local HTTP ComfyUI server.</p>
                                            </div>
                                        </div>
                                    )}
                                </div>
                            </div>
                        )}
                    </div>
                </div>
            </div>

            <div className="border-t border-gray-800 pt-10 flex flex-col gap-6">
                <div className="flex flex-wrap gap-4 justify-end">
                    <button 
                      onClick={handleDeleteSelected} 
                      disabled={selectedFiles.length === 0}
                      className="px-6 py-4 bg-red-600/20 hover:bg-red-600/30 border border-red-600/30 rounded-2xl text-[11px] font-black uppercase text-red-400 flex items-center gap-3 transition-all active:scale-95 shadow-lg disabled:opacity-20 disabled:grayscale"
                    >
                      <TrashIcon className="w-5 h-5"/> Delete Selected ({selectedFiles.length})
                    </button>
                    <button onClick={handleStopTasks} className="px-6 py-4 bg-orange-600/20 hover:bg-orange-600/40 border border-orange-600/30 rounded-2xl text-[11px] font-black uppercase text-orange-400 flex items-center gap-3 transition-all active:scale-95 shadow-lg"><StopIcon className="w-5 h-5"/> Stop Tasks</button>
                    
                    <button onClick={handleBulkQualityCheck} disabled={selectedFiles.length === 0 || !hasValidConfig || isQueueRunning} className="px-6 py-4 bg-blue-600 hover:bg-blue-500 text-white rounded-2xl text-[11px] font-black uppercase flex items-center gap-4 transition-all shadow-xl active:scale-95 disabled:opacity-40">
                      <CheckCircleIcon className="w-5 h-5" /> Check Quality Selected ({selectedFiles.length})
                    </button>

                    <button onClick={handleBulkGenerate} disabled={selectedFiles.length === 0 || !hasValidConfig || isQueueRunning} className="px-10 py-4 bg-green-600 hover:bg-green-500 text-white rounded-2xl text-xs font-black uppercase flex items-center gap-4 transition-all shadow-2xl shadow-green-900/30 active:scale-95 disabled:opacity-40">
                        <SparklesIcon className="w-6 h-6" /> Generate Selected ({selectedFiles.length})
                    </button>
                    
                    <button onClick={handleBulkRefine} disabled={selectedFiles.length === 0 || !hasValidConfig || isQueueRunning} className="px-10 py-4 bg-indigo-600 hover:bg-indigo-500 text-white rounded-2xl text-xs font-black uppercase flex items-center gap-4 transition-all shadow-xl active:scale-95 disabled:opacity-40">
                        <WandIcon className="w-6 h-6" /> Refine Selected ({selectedFiles.length})
                    </button>
                </div>
                <div className="flex flex-wrap gap-4 justify-end">
                    {isComfyEnabled && (
                      <button onClick={handleBulkPreview} disabled={selectedFiles.length === 0} className="px-10 py-4 bg-orange-600 hover:bg-orange-500 text-white rounded-2xl text-xs font-black uppercase flex items-center gap-4 transition-all shadow-xl shadow-orange-900/20 active:scale-95 disabled:opacity-40">
                        <WandIcon className="w-6 h-6" /> Preview Selected ({selectedFiles.length})
                      </button>
                    )}
                    <button onClick={handleExportDataset} disabled={selectedFiles.length === 0 || isExporting} className="w-full sm:w-auto px-16 py-5 bg-indigo-700 hover:bg-indigo-600 text-white rounded-2xl text-xs font-black uppercase flex items-center justify-center gap-4 transition-all shadow-2xl active:scale-95 disabled:opacity-40">
                        {isExporting ? <LoaderIcon className="w-6 h-6 animate-spin" /> : <DownloadIcon className="w-6 h-6" />}
                        {isExporting ? 'Packaging ZIP...' : 'Download Finished Dataset'}
                    </button>
                </div>
            </div>
        </section>

        <section className="bg-gray-900 border border-gray-800 p-8 rounded-3xl shadow-xl overflow-hidden relative">
            <div className="absolute top-0 right-0 p-8 opacity-10 pointer-events-none"><UploadCloudIcon className="w-32 h-32" /></div>
            <h2 className="text-xl font-black mb-6 uppercase tracking-widest text-gray-400">2. Upload Source Media</h2>
            <FileUploader onFilesAdded={handleFilesAdded} />
        </section>
        
        <section className="space-y-8 animate-slide-up min-h-[400px]">
          {mediaFiles && mediaFiles.length > 0 ? (
            <>
              <div className="flex justify-between items-center bg-gray-900/80 backdrop-blur-2xl p-6 rounded-3xl border border-gray-800 sticky top-4 z-40 shadow-[0_20px_50px_-10px_rgba(0,0,0,0.5)]">
                  <div className="flex items-center gap-4">
                      <div className="h-10 w-1.5 bg-indigo-500 rounded-full shadow-[0_0_15px_rgba(99,102,241,0.5)]"></div>
                      <div className="flex flex-col">
                          <h2 className="text-2xl font-black text-white uppercase tracking-tighter leading-none">3. Data Curation Workspace</h2>
                          <p className="text-[10px] font-black text-gray-600 uppercase tracking-widest mt-1">Ready for Parallel Processing ({mediaFiles.length} Loaded)</p>
                      </div>
                  </div>
                  <div className="flex items-center gap-6">
                      <div className="flex items-center gap-3 bg-black px-6 py-3 rounded-2xl border border-gray-800 shadow-inner group active:scale-95 transition-all">
                          <input type="checkbox" id="sel-all" className="h-6 w-6 rounded-lg bg-gray-900 border-gray-700 text-indigo-600 transition-all cursor-pointer shadow-sm" checked={mediaFiles.length > 0 && mediaFiles.every(f => f.isSelected)} onChange={(e) => setMediaFiles(prev => (prev || []).map(mf => ({ ...mf, isSelected: e.target.checked })))} />
                          <label htmlFor="sel-all" className="text-xs font-black text-gray-500 cursor-pointer group-hover:text-gray-300 transition-colors uppercase tracking-widest">Select All Items</label>
                      </div>
                  </div>
              </div>
              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
                {mediaFiles.map(item => (
                  <MediaItem 
                    key={item.id} 
                    item={item} 
                    autofit={autofitTextareas} 
                    isApiKeySet={hasValidConfig} 
                    isComfyEnabled={isComfyEnabled} 
                    showSideBySidePreview={showSideBySidePreview} 
                    onGenerate={handleGenerateCaption} 
                    onCheckQuality={handleCheckQuality}
                    onPreview={handleComfyPreview} 
                    onCaptionChange={(id, cap) => updateFile(id, { caption: cap })} 
                    onCustomInstructionsChange={(id, ins) => updateFile(id, { customInstructions: ins })} 
                    onSelectionChange={(id, sel) => updateFile(id, { isSelected: sel })} 
                    onOpenPreviewModal={setActivePreviewId} 
                  />
                ))}
              </div>
            </>
          ) : (
            <div className="flex flex-col items-center justify-center py-32 bg-gray-900/50 rounded-3xl border-2 border-dashed border-gray-800 text-gray-500 animate-pulse">
                <UploadCloudIcon className="w-16 h-16 mb-6 opacity-20" />
                <h3 className="text-lg font-black uppercase tracking-widest text-gray-700">No items uploaded yet</h3>
                <p className="text-xs mt-2 uppercase tracking-tight text-gray-600">Start by dropping files into the upload zone above</p>
            </div>
          )}
        </section>
      </main>
    </div>
  );
};

export default App;