import React, { useEffect, useState, useCallback } from "react";
import { ArrowLeft, Play, Pause, SkipBack, SkipForward, Plus, RefreshCw, Check, Loader2, ImageIcon, Monitor, Edit3, Wand2, Save, X, Settings, FileText, Sparkles, AlertCircle, Download, Tv, Smartphone, Presentation, Camera, Palette, Star, Lock, Shield, Film, MoreHorizontal, Sliders, ChevronDown, } from "lucide-react";
import { useTVModeStore } from "./studio/stores/tvModeStore";
import { TVModeContainer } from "./studio/components/TVMode/TVModeContainer";
import CreatorStudioSettings, { CREATOR_STUDIO_PARAM_DEFAULTS, } from "./CreatorStudioSettings";
import CreatorExportWizard from "./components/CreatorExportWizard";
/**
 * CreatorStudioEditor - Professional editor for Creator Studio projects
 * Styled like Play Story mode but enhanced for creators
 */
export function CreatorStudioEditor({ projectId, backendUrl, apiKey, onExit, autoGenerateFirst = false, targetSceneCount = 8, defaultLLMModel = "", imageProvider = "comfyui", imageModel, imageWidth = 1344, imageHeight = 768, imageSteps, imageCfg, videoModel, enableVideoGeneration = false, }) {
    const authKey = (apiKey || "").trim();
    const [hasAutoTriggered, setHasAutoTriggered] = useState(false);
    const [hasAutoGeneratedOutline, setHasAutoGeneratedOutline] = useState(false);
    // TV Mode store
    const tvModeActive = useTVModeStore((s) => s.isActive);
    const enterTVMode = useTVModeStore((s) => s.enterTVMode);
    const updateSceneImageByIdx = useTVModeStore((s) => s.updateSceneImageByIdx);
    // State
    const [project, setProject] = useState(null);
    const [scenes, setScenes] = useState([]);
    const [loading, setLoading] = useState(true);
    // Story outline state
    const [storyOutline, setStoryOutline] = useState(null);
    const [isGeneratingOutline, setIsGeneratingOutline] = useState(false);
    const [showOutlinePanel, setShowOutlinePanel] = useState(false);
    const [showExportWizard, setShowExportWizard] = useState(false);
    // Scene editor state
    const [showSceneEditor, setShowSceneEditor] = useState(false);
    const [editingScene, setEditingScene] = useState(null);
    const [editNarration, setEditNarration] = useState("");
    const [editImagePrompt, setEditImagePrompt] = useState("");
    const [editNegativePrompt, setEditNegativePrompt] = useState("");
    const [isSavingScene, setIsSavingScene] = useState(false);
    // Model selection state
    const [availableLLMModels, setAvailableLLMModels] = useState([]);
    const [availableImageModels, setAvailableImageModels] = useState([]);
    const [selectedLLMModel, setSelectedLLMModel] = useState(defaultLLMModel);
    const [selectedImageModel, setSelectedImageModel] = useState(imageModel || "");
    const [selectedVideoModel, setSelectedVideoModel] = useState(videoModel || "");
    const [settingsLLMModel, setSettingsLLMModel] = useState(defaultLLMModel);
    const [error, setError] = useState(null);
    const [currentSceneIndex, setCurrentSceneIndex] = useState(0);
    const [isPlaying, setIsPlaying] = useState(false);
    const [isTTSSpeaking, setIsTTSSpeaking] = useState(false);
    const [isSaving, setIsSaving] = useState(false);
    const [lastSaved, setLastSaved] = useState(null);
    const [isGeneratingScene, setIsGeneratingScene] = useState(false);
    const [isGeneratingImage, setIsGeneratingImage] = useState(false);
    const [isGeneratingVideo, setIsGeneratingVideo] = useState(false);
    const [hoveredSceneIdx, setHoveredSceneIdx] = useState(null);
    const [canPlayWebm, setCanPlayWebm] = useState(true);
    // Batch generation state (generates all scenes from outline)
    const [isBatchGenerating, setIsBatchGenerating] = useState(false);
    const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0, phase: 'scene' });
    // Project Settings Modal state
    const [showSettingsModal, setShowSettingsModal] = useState(false);
    const [settingsTitle, setSettingsTitle] = useState("");
    const [settingsLogline, setSettingsLogline] = useState("");
    const [settingsPlatform, setSettingsPlatform] = useState("youtube_16_9");
    const [settingsGoal, setSettingsGoal] = useState("Educate");
    const [settingsVisualStyle, setSettingsVisualStyle] = useState("Cinematic");
    const [settingsTones, setSettingsTones] = useState(["Documentary", "Calm"]);
    const [settingsSceneCount, setSettingsSceneCount] = useState(8);
    const [settingsSceneDuration, setSettingsSceneDuration] = useState(5);
    const [settingsLockIdentity, setSettingsLockIdentity] = useState(true);
    const [settingsContentRating, setSettingsContentRating] = useState("sfw");
    const [settingsEnableVideo, setSettingsEnableVideo] = useState(false); // Enable video generation capability
    const [isSavingSettings, setIsSavingSettings] = useState(false);
    // Model override state for Project Settings
    const [settingsImageModel, setSettingsImageModel] = useState("");
    const [settingsVideoModel, setSettingsVideoModel] = useState("");
    const [availableVideoModels, setAvailableVideoModels] = useState([]);
    const [loadingModels, setLoadingModels] = useState(false);
    // Generation parameters state (advanced customization)
    const [genParams, setGenParams] = useState(CREATOR_STUDIO_PARAM_DEFAULTS);
    // Project-level capability: can this project generate videos?
    // IMPORTANT: do NOT rely only on enableVideoGeneration (wizard-only, transient)
    // This derives video capability from project metadata/tags for existing projects
    const projectWantsVideo = Boolean(project?.metadata?.generationMode === "video" ||
        project?.tags?.includes("mode:video") ||
        project?.tags?.includes("projectType:video") ||
        project?.tags?.includes("projectType:video_series") ||
        enableVideoGeneration === true // backward compatibility with wizard prop
    );
    // API helpers
    const fetchApi = useCallback(async (path) => {
        const url = `${backendUrl.replace(/\/+$/, "")}${path}`;
        const res = await fetch(url, {
            method: "GET",
            headers: {
                "Content-Type": "application/json",
                ...(authKey ? { "x-api-key": authKey } : {}),
            },
        });
        if (!res.ok) {
            const text = await res.text().catch(() => "");
            throw new Error(`HTTP ${res.status}${text ? `: ${text}` : ""}`);
        }
        return (await res.json());
    }, [backendUrl, authKey]);
    const postApi = useCallback(async (path, body) => {
        const url = `${backendUrl.replace(/\/+$/, "")}${path}`;
        const res = await fetch(url, {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                ...(authKey ? { "x-api-key": authKey } : {}),
            },
            body: JSON.stringify(body),
        });
        if (!res.ok) {
            const text = await res.text().catch(() => "");
            throw new Error(`HTTP ${res.status}${text ? `: ${text}` : ""}`);
        }
        return (await res.json());
    }, [backendUrl, authKey]);
    const patchApi = useCallback(async (path, body) => {
        const url = `${backendUrl.replace(/\/+$/, "")}${path}`;
        const res = await fetch(url, {
            method: "PATCH",
            headers: {
                "Content-Type": "application/json",
                ...(authKey ? { "x-api-key": authKey } : {}),
            },
            body: JSON.stringify(body),
        });
        if (!res.ok) {
            const text = await res.text().catch(() => "");
            throw new Error(`HTTP ${res.status}${text ? `: ${text}` : ""}`);
        }
        return (await res.json());
    }, [backendUrl, authKey]);
    const deleteApi = useCallback(async (path) => {
        const url = `${backendUrl.replace(/\/+$/, "")}${path}`;
        const res = await fetch(url, {
            method: "DELETE",
            headers: {
                "Content-Type": "application/json",
                ...(authKey ? { "x-api-key": authKey } : {}),
            },
        });
        if (!res.ok) {
            const text = await res.text().catch(() => "");
            throw new Error(`HTTP ${res.status}${text ? `: ${text}` : ""}`);
        }
        return (await res.json());
    }, [backendUrl, authKey]);
    // ---------- API <-> UI normalization helpers ----------
    // Backend may return snake_case (image_url/video_url). UI uses camelCase (imageUrl/videoUrl).
    const normalizeScene = useCallback((raw) => {
        return {
            id: raw.id,
            videoId: raw.videoId ?? raw.video_id ?? "",
            idx: raw.idx ?? raw.index ?? raw.scene_index ?? 0,
            narration: raw.narration ?? "",
            imagePrompt: raw.imagePrompt ?? raw.image_prompt ?? "",
            negativePrompt: raw.negativePrompt ?? raw.negative_prompt ?? "",
            imageUrl: raw.imageUrl ?? raw.image_url ?? null,
            videoUrl: raw.videoUrl ?? raw.video_url ?? null,
            audioUrl: raw.audioUrl ?? raw.audio_url ?? null,
            status: raw.status ?? "pending",
            durationSec: raw.durationSec ?? raw.duration_sec ?? 5,
            createdAt: raw.createdAt ?? raw.created_at ?? 0,
            updatedAt: raw.updatedAt ?? raw.updated_at ?? 0,
        };
    }, []);
    const normalizeScenes = useCallback((arr) => {
        if (!Array.isArray(arr))
            return [];
        return arr.map(normalizeScene).sort((a, b) => a.idx - b.idx);
    }, [normalizeScene]);
    // Convert UI patch (camelCase) to backend-friendly payload (include snake_case too)
    const toScenePatch = useCallback((patch) => {
        const out = { ...patch };
        if ("imageUrl" in out)
            out.image_url = out.imageUrl;
        if ("videoUrl" in out)
            out.video_url = out.videoUrl;
        if ("audioUrl" in out)
            out.audio_url = out.audioUrl;
        if ("imagePrompt" in out)
            out.image_prompt = out.imagePrompt;
        if ("negativePrompt" in out)
            out.negative_prompt = out.negativePrompt;
        if ("durationSec" in out)
            out.duration_sec = out.durationSec;
        return out;
    }, []);
    // Authoritative refresh from backend (source of truth)
    const refreshScenes = useCallback(async () => {
        try {
            const scenesRes = await fetchApi(`/studio/videos/${projectId}/scenes`);
            setScenes(normalizeScenes(scenesRes.scenes));
        }
        catch (e) {
            // Non-critical - log but don't alert
            console.warn('[CreatorStudioEditor] Failed to refresh scenes:', e);
        }
    }, [fetchApi, projectId, normalizeScenes]);
    // Proxy video URL through backend for correct Content-Type headers
    // This ensures WebM videos play correctly in browsers
    const proxyVideoUrl = useCallback((rawUrl) => {
        if (!rawUrl)
            return null;
        // Only proxy ComfyUI localhost URLs
        if (rawUrl.startsWith('http://localhost:8188/') || rawUrl.startsWith('http://127.0.0.1:8188/')) {
            return `${backendUrl.replace(/\/+$/, '')}/studio/media?url=${encodeURIComponent(rawUrl)}`;
        }
        // Already proxied or external URL - return as-is
        return rawUrl;
    }, [backendUrl]);
    // Detect when "videoUrl" is actually an animated image (e.g. .webp, .gif)
    // Some Comfy workflows output animated WebP instead of WebM when ffmpeg is unavailable
    const isAnimatedImageUrl = useCallback((u) => {
        if (!u)
            return false;
        const s = u.toLowerCase();
        // Covers direct URLs and ComfyUI view?filename=... patterns
        return s.includes(".webp") || s.includes(".gif");
    }, []);
    // Detect if URL is a WebM video
    const isWebmUrl = useCallback((u) => {
        if (!u)
            return false;
        return u.toLowerCase().includes(".webm");
    }, []);
    // Sync outline with current scenes (keeps outline in sync with actual scene data)
    const syncOutlineWithScenes = useCallback(async () => {
        if (!projectId)
            return;
        try {
            console.log('[CreatorStudioEditor] Syncing outline with scenes...');
            const data = await postApi(`/studio/videos/${projectId}/sync-outline`, {});
            if (data.ok && data.outline) {
                setStoryOutline(data.outline);
                console.log(`[CreatorStudioEditor] Outline synced: ${data.scene_count} scenes`);
            }
        }
        catch (e) {
            console.warn('[CreatorStudioEditor] Failed to sync outline:', e.message);
            // Non-critical - don't alert user
        }
    }, [projectId, postApi]);
    // Generate AI-powered story outline
    const generateStoryOutline = useCallback(async () => {
        if (!project || isGeneratingOutline)
            return;
        setIsGeneratingOutline(true);
        try {
            console.log('[CreatorStudioEditor] Generating story outline...');
            const data = await postApi(`/studio/videos/${projectId}/generate-outline`, {
                target_scenes: targetSceneCount,
                scene_duration: 5,
                ollama_model: selectedLLMModel || undefined,
            });
            if (data.ok && data.outline) {
                setStoryOutline(data.outline);
                console.log('[CreatorStudioEditor] Story outline generated:', data.outline.title);
            }
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to generate outline:', e);
            alert(`Failed to generate outline: ${e.message}`);
        }
        finally {
            setIsGeneratingOutline(false);
        }
    }, [project, projectId, targetSceneCount, selectedLLMModel, isGeneratingOutline, postApi]);
    // Load existing story outline
    const loadStoryOutline = useCallback(async () => {
        try {
            const data = await fetchApi(`/studio/videos/${projectId}/outline`);
            if (data.ok && data.outline) {
                setStoryOutline(data.outline);
            }
        }
        catch (e) {
            console.log('[CreatorStudioEditor] No existing outline found');
        }
    }, [projectId, fetchApi]);
    // Open scene editor
    const openSceneEditor = useCallback((scene) => {
        setEditingScene(scene);
        setEditNarration(scene.narration || "");
        setEditImagePrompt(scene.imagePrompt || "");
        setEditNegativePrompt(scene.negativePrompt || "");
        setShowSceneEditor(true);
    }, []);
    // Save scene edits
    const saveSceneEdits = useCallback(async () => {
        if (!editingScene)
            return;
        setIsSavingScene(true);
        try {
            await patchApi(`/studio/videos/${projectId}/scenes/${editingScene.id}`, {
                narration: editNarration,
                imagePrompt: editImagePrompt,
                negativePrompt: editNegativePrompt,
            });
            setScenes((prev) => prev.map((s) => s.id === editingScene.id
                ? { ...s, narration: editNarration, imagePrompt: editImagePrompt, negativePrompt: editNegativePrompt }
                : s));
            setLastSaved(new Date());
            setShowSceneEditor(false);
            setEditingScene(null);
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to save scene:', e);
            alert(`Failed to save scene: ${e.message}`);
        }
        finally {
            setIsSavingScene(false);
        }
    }, [editingScene, editNarration, editImagePrompt, editNegativePrompt, projectId, patchApi]);
    // Parse tags from project
    const parseTagsFromProject = useCallback((proj) => {
        const tags = proj.tags || [];
        let goal = "Educate";
        let visualStyle = "Cinematic";
        let tones = [];
        let lockIdentity = true;
        let sceneCount = 8;
        let sceneDuration = 5;
        tags.forEach((tag) => {
            if (tag.startsWith("goal:")) {
                const g = tag.replace("goal:", "");
                if (g === "entertain")
                    goal = "Entertain";
                else if (g === "educate")
                    goal = "Educate";
                else if (g === "inspire")
                    goal = "Inspire";
            }
            else if (tag.startsWith("visual:")) {
                const v = tag.replace("visual:", "").replace(/_/g, " ");
                if (v.toLowerCase() === "cinematic")
                    visualStyle = "Cinematic";
                else if (v.toLowerCase() === "digital art")
                    visualStyle = "Digital Art";
                else if (v.toLowerCase() === "anime")
                    visualStyle = "Anime";
            }
            else if (tag.startsWith("tone:")) {
                const t = tag.replace("tone:", "").replace(/_/g, " ");
                const capitalizedTone = t.charAt(0).toUpperCase() + t.slice(1);
                tones.push(capitalizedTone);
            }
            else if (tag === "lock:identity") {
                lockIdentity = true;
            }
            else if (tag.startsWith("scenes:")) {
                sceneCount = parseInt(tag.replace("scenes:", ""), 10) || 8;
            }
            else if (tag.startsWith("duration:")) {
                sceneDuration = parseInt(tag.replace("duration:", ""), 10) || 5;
            }
        });
        return { goal, visualStyle, tones, lockIdentity, sceneCount, sceneDuration };
    }, []);
    // Parse generation params from project tags
    const parseGenParamsFromTags = useCallback((tags) => {
        const t = tags || [];
        const next = { ...CREATOR_STUDIO_PARAM_DEFAULTS };
        const get = (k) => t.find(x => x.startsWith(`gen:${k}=`))?.split("=")[1];
        next.enabled = get("enabled") === "1";
        next.steps = Number(get("steps") ?? next.steps);
        next.cfgScale = Number(get("cfg") ?? next.cfgScale);
        next.creativity = Number(get("creativity") ?? next.creativity);
        next.lockSeed = get("seedlock") === "1";
        next.seed = Number(get("seed") ?? next.seed);
        return next;
    }, []);
    // Open settings modal
    const openSettingsModal = useCallback(async () => {
        if (!project)
            return;
        setSettingsTitle(project.title || "");
        setSettingsLogline(project.logline || "");
        setSettingsPlatform(project.platformPreset || "youtube_16_9");
        setSettingsContentRating(project.contentRating || "sfw");
        const parsed = parseTagsFromProject(project);
        setSettingsGoal(parsed.goal);
        setSettingsVisualStyle(parsed.visualStyle);
        setSettingsTones(parsed.tones.length > 0 ? parsed.tones : ["Documentary", "Calm"]);
        setSettingsSceneCount(parsed.sceneCount);
        setSettingsSceneDuration(parsed.sceneDuration);
        setSettingsLockIdentity(parsed.lockIdentity);
        // Set the LLM model from current selection or project tags
        const tags = project.tags || [];
        const llmTag = tags.find((t) => t.startsWith("llm:"));
        setSettingsLLMModel(llmTag ? llmTag.replace("llm:", "") : selectedLLMModel);
        // Initialize video generation enabled state from tags or enableVideoGeneration prop
        const hasVideoMode = tags.includes("mode:video") ||
            tags.includes("projectType:video") ||
            tags.includes("projectType:video_series") ||
            project?.metadata?.generationMode === "video" ||
            enableVideoGeneration === true;
        setSettingsEnableVideo(hasVideoMode);
        // Initialize generation params from project tags
        const parsedGenParams = parseGenParamsFromTags(tags);
        // Also restore negative prompt from localStorage
        try {
            const key = `creatorstudio:genparams:${projectId}:neg`;
            const stored = localStorage.getItem(key);
            if (stored) {
                const neg = JSON.parse(stored);
                parsedGenParams.useCustomNegativePrompt = Boolean(neg?.use);
                parsedGenParams.customNegativePrompt = String(neg?.text || "");
            }
        }
        catch { }
        setGenParams(parsedGenParams);
        // Initialize image/video model overrides from project tags or props
        const imageModelTag = tags.find((t) => t.startsWith("imageModel:"));
        setSettingsImageModel(imageModelTag?.replace("imageModel:", "") || imageModel || "");
        const videoModelTag = tags.find((t) => t.startsWith("videoModel:"));
        setSettingsVideoModel(videoModelTag?.replace("videoModel:", "") || videoModel || "");
        // Fetch available models to ensure the dropdowns are populated
        setLoadingModels(true);
        try {
            // Fetch LLM, Image, and Video models in parallel
            const [llmData, imgData, vidData] = await Promise.all([
                fetchApi('/models?provider=ollama'),
                fetchApi('/models?provider=comfyui&model_type=image'),
                fetchApi('/models?provider=comfyui&model_type=video'),
            ]);
            if (llmData.models) {
                const models = llmData.models.map(m => ({ id: m.id, name: m.name || m.id }));
                setAvailableLLMModels(models);
            }
            if (imgData.models) {
                const models = imgData.models.map(m => ({ id: m, name: m }));
                setAvailableImageModels(models);
            }
            if (vidData.models) {
                const models = vidData.models.map(m => ({ id: m, name: m }));
                setAvailableVideoModels(models);
            }
        }
        catch (e) {
            console.log('[CreatorStudioEditor] Failed to fetch models for settings:', e);
        }
        finally {
            setLoadingModels(false);
        }
        setShowSettingsModal(true);
    }, [project, projectId, parseTagsFromProject, parseGenParamsFromTags, selectedLLMModel, imageModel, videoModel, enableVideoGeneration, fetchApi]);
    // Toggle tone in settings
    const toggleSettingsTone = useCallback((tone) => {
        setSettingsTones((prev) => {
            if (prev.includes(tone)) {
                return prev.filter((t) => t !== tone);
            }
            return [...prev, tone];
        });
    }, []);
    // Build tags from settings
    const buildTagsFromSettings = useCallback(() => {
        const tags = [];
        // Video generation mode - critical for "Make Video" button visibility
        tags.push(`mode:${settingsEnableVideo ? "video" : "slideshow"}`);
        if (settingsGoal)
            tags.push(`goal:${settingsGoal.toLowerCase()}`);
        if (settingsVisualStyle)
            tags.push(`visual:${settingsVisualStyle.toLowerCase().replace(/ /g, "_")}`);
        settingsTones.forEach((t) => tags.push(`tone:${t.toLowerCase().replace(/ /g, "_")}`));
        if (settingsLockIdentity)
            tags.push("lock:identity");
        tags.push(`scenes:${settingsSceneCount}`);
        tags.push(`duration:${settingsSceneDuration}`);
        if (settingsLLMModel)
            tags.push(`llm:${settingsLLMModel}`);
        // Model overrides - allows per-project model selection
        if (settingsImageModel)
            tags.push(`imageModel:${settingsImageModel}`);
        if (settingsVideoModel)
            tags.push(`videoModel:${settingsVideoModel}`);
        return tags;
    }, [settingsEnableVideo, settingsGoal, settingsVisualStyle, settingsTones, settingsLockIdentity, settingsSceneCount, settingsSceneDuration, settingsLLMModel, settingsImageModel, settingsVideoModel]);
    // Build tags including generation params
    const buildGenTags = useCallback((p) => {
        // Start with base settings tags, filter out any existing gen:* tags
        const tags = buildTagsFromSettings().filter(t => !t.startsWith("gen:"));
        // Add generation params
        tags.push(`gen:enabled=${p.enabled ? "1" : "0"}`);
        tags.push(`gen:steps=${p.steps}`);
        tags.push(`gen:cfg=${p.cfgScale}`);
        tags.push(`gen:creativity=${p.creativity}`);
        tags.push(`gen:seedlock=${p.lockSeed ? "1" : "0"}`);
        tags.push(`gen:seed=${p.seed}`);
        return tags;
    }, [buildTagsFromSettings]);
    // Save project settings
    const saveProjectSettings = useCallback(async () => {
        if (!project)
            return;
        setIsSavingSettings(true);
        try {
            const tags = buildGenTags(genParams);
            await patchApi(`/studio/videos/${projectId}`, {
                title: settingsTitle.trim(),
                logline: settingsLogline.trim(),
                platformPreset: settingsPlatform,
                contentRating: settingsContentRating,
                tags,
            });
            // Persist negative prompt locally (can be long, so not in tags)
            try {
                const key = `creatorstudio:genparams:${projectId}:neg`;
                localStorage.setItem(key, JSON.stringify({
                    use: genParams.useCustomNegativePrompt,
                    text: genParams.customNegativePrompt,
                }));
            }
            catch { }
            // Update local project state
            setProject((prev) => prev ? {
                ...prev,
                title: settingsTitle.trim(),
                logline: settingsLogline.trim(),
                platformPreset: settingsPlatform,
                contentRating: settingsContentRating,
                tags,
            } : null);
            // Update selected models to match settings
            setSelectedLLMModel(settingsLLMModel);
            if (settingsImageModel)
                setSelectedImageModel(settingsImageModel);
            if (settingsVideoModel)
                setSelectedVideoModel(settingsVideoModel);
            setLastSaved(new Date());
            setShowSettingsModal(false);
            console.log('[CreatorStudioEditor] Project settings saved');
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to save settings:', e);
            alert(`Failed to save settings: ${e.message}`);
        }
        finally {
            setIsSavingSettings(false);
        }
    }, [project, projectId, settingsTitle, settingsLogline, settingsPlatform, settingsContentRating, settingsLLMModel, settingsImageModel, settingsVideoModel, genParams, buildGenTags, patchApi]);
    // Delete scene
    const deleteScene = useCallback(async (sceneId) => {
        if (scenes.length <= 1) {
            alert("Cannot delete the last scene.");
            return;
        }
        if (!window.confirm("Delete this scene? This cannot be undone.")) {
            return;
        }
        try {
            console.log('[CreatorStudioEditor] Deleting scene:', sceneId);
            await deleteApi(`/studio/videos/${projectId}/scenes/${sceneId}`);
            const deletedIndex = scenes.findIndex((s) => s.id === sceneId);
            setScenes((prev) => {
                const newScenes = prev
                    .filter((s) => s.id !== sceneId)
                    .map((s, i) => ({ ...s, idx: i }));
                return newScenes;
            });
            if (deletedIndex >= 0 && deletedIndex <= currentSceneIndex) {
                setCurrentSceneIndex((prev) => Math.max(0, prev - 1));
            }
            setLastSaved(new Date());
            console.log('[CreatorStudioEditor] Scene deleted successfully');
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to delete scene:', e);
            alert(`Failed to delete scene: ${e.message}`);
        }
    }, [projectId, scenes, currentSceneIndex, deleteApi]);
    // Fetch available models
    const fetchAvailableModels = useCallback(async () => {
        try {
            const llmData = await fetchApi('/models?provider=ollama');
            if (llmData.models) {
                const models = llmData.models.map(m => ({ id: m.id, name: m.name || m.id }));
                setAvailableLLMModels(models);
                // Auto-select a model if none selected
                if (!selectedLLMModel && models.length > 0) {
                    // Prefer llama3:8b if available, otherwise first model
                    const preferred = models.find(m => m.id === "llama3:8b") || models[0];
                    setSelectedLLMModel(preferred.id);
                    setSettingsLLMModel(preferred.id);
                }
            }
        }
        catch (e) {
            console.log('[CreatorStudioEditor] Failed to fetch LLM models:', e);
        }
        try {
            const imgData = await fetchApi('/models?provider=comfyui&model_type=image');
            if (imgData.models) {
                setAvailableImageModels(imgData.models.map(m => ({ id: m, name: m })));
            }
        }
        catch (e) {
            console.log('[CreatorStudioEditor] Failed to fetch image models:', e);
        }
    }, [fetchApi, selectedLLMModel]);
    // Convert Creator Studio scene to TV Mode scene format
    const sceneToTVScene = useCallback((scene) => {
        return {
            idx: scene.idx,
            narration: scene.narration || "",
            image_prompt: scene.imagePrompt || "",
            negative_prompt: scene.negativePrompt || "",
            duration_s: scene.durationSec || 5,
            tags: {},
            image_url: scene.imageUrl || null,
            status: scene.status === "ready" ? "ready" : "pending",
            imageStatus: scene.imageUrl ? "ready" : "pending",
        };
    }, []);
    // Enter TV Mode with current scenes
    const handleEnterTVMode = useCallback(() => {
        if (!project || scenes.length === 0)
            return;
        const tvScenes = scenes.map(sceneToTVScene);
        enterTVMode(projectId, project.title, tvScenes, currentSceneIndex);
    }, [project, projectId, scenes, currentSceneIndex, enterTVMode, sceneToTVScene]);
    // Editor playback with TTS - speak scene narration when playing
    useEffect(() => {
        if (!isPlaying || scenes.length === 0) {
            // Stop any ongoing speech when not playing
            if (window.SpeechService?.stopSpeaking) {
                window.SpeechService.stopSpeaking();
            }
            setIsTTSSpeaking(false);
            return;
        }
        const currentScene = scenes[currentSceneIndex];
        if (!currentScene?.narration) {
            // No narration, advance to next scene after a short delay
            const timer = setTimeout(() => {
                if (currentSceneIndex < scenes.length - 1) {
                    setCurrentSceneIndex((i) => i + 1);
                }
                else {
                    setIsPlaying(false); // End of scenes
                }
            }, 2000);
            return () => clearTimeout(timer);
        }
        // Speak the current scene's narration
        const svc = window.SpeechService;
        if (!svc?.speak) {
            // Fallback if no TTS - use fixed timer
            const timer = setTimeout(() => {
                if (currentSceneIndex < scenes.length - 1) {
                    setCurrentSceneIndex((i) => i + 1);
                }
                else {
                    setIsPlaying(false);
                }
            }, 5000);
            return () => clearTimeout(timer);
        }
        console.log(`[Editor] Speaking scene ${currentSceneIndex + 1} narration...`);
        setIsTTSSpeaking(true);
        svc.speak(currentScene.narration, {
            onStart: () => setIsTTSSpeaking(true),
            onEnd: () => {
                setIsTTSSpeaking(false);
                // Auto-advance to next scene after narration finishes
                if (currentSceneIndex < scenes.length - 1) {
                    setCurrentSceneIndex((i) => i + 1);
                }
                else {
                    setIsPlaying(false); // End of scenes
                }
            },
            onError: () => {
                setIsTTSSpeaking(false);
                // On error, advance anyway after delay
                setTimeout(() => {
                    if (currentSceneIndex < scenes.length - 1) {
                        setCurrentSceneIndex((i) => i + 1);
                    }
                    else {
                        setIsPlaying(false);
                    }
                }, 2000);
            },
        });
        return () => {
            svc.stopSpeaking?.();
        };
    }, [isPlaying, currentSceneIndex, scenes]);
    // Generate image for a scene
    const generateImageForScene = useCallback(async (sceneId, imagePrompt, force = false) => {
        if (isGeneratingImage && !force) {
            console.log('[CreatorStudioEditor] Already generating image, skipping');
            return;
        }
        setIsGeneratingImage(true);
        console.log('[CreatorStudioEditor] Generating image for scene:', sceneId);
        try {
            const llmProvider = imageProvider === 'comfyui' ? 'ollama' : imageProvider;
            // Apply generation parameters if enabled
            const effectiveSteps = genParams.enabled ? genParams.steps : imageSteps;
            const effectiveCfg = genParams.enabled ? genParams.cfgScale : imageCfg;
            // Get scene-level negative prompt if available
            const scene = scenes.find(s => s.id === sceneId);
            const sceneNeg = scene?.negativePrompt || "";
            const combinedNegativePrompt = (genParams.enabled && genParams.useCustomNegativePrompt && genParams.customNegativePrompt.trim())
                ? [sceneNeg, genParams.customNegativePrompt.trim()].filter(Boolean).join(", ")
                : sceneNeg || undefined;
            // Send explicit width/height from wizard selection to backend
            // This ensures the resolution selected in Step 2 is actually used
            const data = await postApi('/chat', {
                message: `imagine ${imagePrompt}`,
                mode: 'imagine',
                provider: llmProvider,
                imgModel: selectedImageModel || imageModel || undefined,
                // Pass explicit resolution from wizard (if available)
                // Backend will use these values directly instead of computing from aspect ratio
                ...(imageWidth ? { imgWidth: imageWidth } : {}),
                ...(imageHeight ? { imgHeight: imageHeight } : {}),
                imgSteps: effectiveSteps,
                imgCfg: effectiveCfg,
                negativePrompt: combinedNegativePrompt,
                imgSeed: genParams.enabled && genParams.lockSeed ? genParams.seed : undefined,
                creativity: genParams.enabled ? genParams.creativity : undefined,
                promptRefinement: false,
            });
            const imageUrl = data?.media?.images?.[0];
            if (imageUrl) {
                console.log('[CreatorStudioEditor] Image generated:', imageUrl);
                await patchApi(`/studio/videos/${projectId}/scenes/${sceneId}`, toScenePatch({
                    imageUrl,
                    status: 'ready',
                }));
                setScenes((prev) => prev.map((s) => s.id === sceneId ? { ...s, imageUrl, status: 'ready' } : s));
                setLastSaved(new Date());
            }
            else {
                console.warn('[CreatorStudioEditor] No image returned from backend');
            }
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to generate image:', e);
        }
        finally {
            setIsGeneratingImage(false);
        }
    }, [projectId, imageProvider, imageModel, selectedImageModel, imageWidth, imageHeight, imageSteps, imageCfg, postApi, patchApi, isGeneratingImage, toScenePatch, genParams, scenes]);
    // Generate video for a scene (converts image to video)
    const generateVideoForScene = useCallback(async (sceneId, imageUrl, prompt) => {
        if (isGeneratingVideo) {
            console.log('[CreatorStudioEditor] Already generating video, skipping');
            return;
        }
        if (!imageUrl) {
            console.warn('[CreatorStudioEditor] No image URL to animate');
            return;
        }
        setIsGeneratingVideo(true);
        console.log('[CreatorStudioEditor] Generating video for scene:', sceneId);
        try {
            // IMPORTANT:
            // Backend animate mode detects the reference image via URL in the message (in this project version).
            // Backend also expects vidModel (not videoModel).
            const data = await postApi('/chat', {
                message: `${prompt || 'Animate this scene with subtle motion'} ${imageUrl}`,
                mode: 'animate',
                provider: 'ollama',
                vidModel: selectedVideoModel || videoModel || undefined,
                // Apply generation parameters if enabled
                vidSeed: genParams.enabled && genParams.lockSeed ? genParams.seed : undefined,
                vidSteps: genParams.enabled ? genParams.steps : undefined,
                vidCfg: genParams.enabled ? genParams.cfgScale : undefined,
                creativity: genParams.enabled ? genParams.creativity : undefined,
            });
            // Backend returns media.video_url (NOT always media.videos[]).
            const rawVideoUrl = data?.media?.video_url ||
                data?.media?.videos?.[0] ||
                null;
            if (rawVideoUrl) {
                // Proxy the URL for correct Content-Type headers (WebM playback)
                const proxiedVideoUrl = proxyVideoUrl(rawVideoUrl) || rawVideoUrl;
                console.log('[CreatorStudioEditor] Video generated:', rawVideoUrl, '-> proxied:', proxiedVideoUrl);
                await patchApi(`/studio/videos/${projectId}/scenes/${sceneId}`, toScenePatch({
                    videoUrl: proxiedVideoUrl,
                    status: 'ready',
                }));
                setScenes((prev) => prev.map((s) => s.id === sceneId ? { ...s, videoUrl: proxiedVideoUrl, status: 'ready' } : s));
                setLastSaved(new Date());
            }
            else {
                console.warn('[CreatorStudioEditor] No video returned from backend');
            }
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to generate video:', e);
        }
        finally {
            setIsGeneratingVideo(false);
        }
    }, [projectId, videoModel, selectedVideoModel, postApi, patchApi, isGeneratingVideo, toScenePatch, proxyVideoUrl, genParams]);
    // Remove video and fall back to image-only for a scene
    const removeVideoForScene = useCallback(async (sceneId) => {
        if (!window.confirm("Remove the video for this scene and keep the image?"))
            return;
        try {
            await patchApi(`/studio/videos/${projectId}/scenes/${sceneId}`, toScenePatch({ videoUrl: null, status: 'ready' }));
            setScenes(prev => prev.map(s => (s.id === sceneId ? { ...s, videoUrl: null, status: 'ready' } : s)));
            setLastSaved(new Date());
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to remove video:', e);
            alert(`Failed to remove video: ${e.message}`);
        }
    }, [projectId, patchApi, toScenePatch]);
    // Generate scene from outline
    const generateSceneFromOutline = useCallback(async (sceneIndex) => {
        if (!storyOutline || sceneIndex >= storyOutline.scenes.length)
            return;
        setIsGeneratingScene(true);
        try {
            const data = await postApi(`/studio/videos/${projectId}/scenes/generate-from-outline?scene_index=${sceneIndex}`, {});
            if (data.ok && data.scene) {
                setScenes((prev) => [...prev, data.scene]);
                setCurrentSceneIndex(scenes.length);
                setLastSaved(new Date());
                generateImageForScene(data.scene.id, data.scene.imagePrompt);
            }
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to generate scene from outline:', e);
            alert(`Failed to generate scene: ${e.message}`);
        }
        finally {
            setIsGeneratingScene(false);
        }
    }, [projectId, storyOutline, scenes.length, postApi, generateImageForScene]);
    // Generate ALL scenes from outline in sequence (batch generation)
    const generateAllScenesFromOutline = useCallback(async () => {
        if (!storyOutline || !storyOutline.scenes || storyOutline.scenes.length === 0) {
            console.log('[CreatorStudioEditor] No outline scenes to generate');
            return;
        }
        const totalScenes = storyOutline.scenes.length;
        console.log(`[CreatorStudioEditor] Starting batch generation of ${totalScenes} scenes`);
        setIsBatchGenerating(true);
        setBatchProgress({ current: 0, total: totalScenes, phase: 'scene' });
        const generatedScenes = [];
        try {
            // Generate all scenes first (without images for speed)
            for (let i = 0; i < totalScenes; i++) {
                setBatchProgress({ current: i + 1, total: totalScenes, phase: 'scene' });
                console.log(`[CreatorStudioEditor] Generating scene ${i + 1}/${totalScenes}`);
                try {
                    const data = await postApi(`/studio/videos/${projectId}/scenes/generate-from-outline?scene_index=${i}`, {});
                    if (data.ok && data.scene) {
                        generatedScenes.push(data.scene);
                        setScenes((prev) => [...prev, data.scene]);
                        setCurrentSceneIndex(i);
                    }
                }
                catch (sceneErr) {
                    console.error(`[CreatorStudioEditor] Failed to generate scene ${i + 1}:`, sceneErr);
                    // Continue with remaining scenes even if one fails
                }
                // Small delay between scene creations to avoid overwhelming the server
                if (i < totalScenes - 1) {
                    await new Promise(resolve => setTimeout(resolve, 200));
                }
            }
            console.log(`[CreatorStudioEditor] Created ${generatedScenes.length} scenes, now generating images...`);
            // Phase 2: Generate images for all scenes
            const scenesWithImages = [];
            for (let i = 0; i < generatedScenes.length; i++) {
                const scene = generatedScenes[i];
                setBatchProgress({ current: i + 1, total: generatedScenes.length, phase: 'image' });
                console.log(`[CreatorStudioEditor] Generating image ${i + 1}/${generatedScenes.length}`);
                try {
                    // Generate image inline (can't use generateImageForScene due to isGeneratingImage lock)
                    const llmProvider = imageProvider === 'comfyui' ? 'ollama' : imageProvider;
                    const data = await postApi('/chat', {
                        message: `imagine ${scene.imagePrompt}`,
                        mode: 'imagine',
                        provider: llmProvider,
                        imgModel: selectedImageModel || imageModel || undefined,
                        imgAspectRatio: '16:9',
                        imgSteps: imageSteps,
                        imgCfg: imageCfg,
                        promptRefinement: false,
                    });
                    const imageUrl = data?.media?.images?.[0];
                    if (imageUrl) {
                        await patchApi(`/studio/videos/${projectId}/scenes/${scene.id}`, toScenePatch({
                            imageUrl,
                            status: projectWantsVideo ? 'generating' : 'ready',
                        }));
                        setScenes((prev) => prev.map((s) => s.id === scene.id ? { ...s, imageUrl, status: (projectWantsVideo ? 'generating' : 'ready') } : s));
                        scenesWithImages.push({ scene, imageUrl });
                    }
                }
                catch (imgErr) {
                    console.error(`[CreatorStudioEditor] Failed to generate image for scene ${i + 1}:`, imgErr);
                    // Continue with remaining images
                }
            }
            // Phase 3: Generate videos from images (if enabled)
            if (projectWantsVideo && scenesWithImages.length > 0) {
                console.log(`[CreatorStudioEditor] Phase 3: Generating ${scenesWithImages.length} videos...`);
                for (let i = 0; i < scenesWithImages.length; i++) {
                    const { scene, imageUrl } = scenesWithImages[i];
                    setBatchProgress({ current: i + 1, total: scenesWithImages.length, phase: 'video' });
                    console.log(`[CreatorStudioEditor] Generating video ${i + 1}/${scenesWithImages.length}`);
                    try {
                        // Use the animate endpoint to generate video from image
                        // IMPORTANT: Include imageUrl in message and use vidModel (not videoModel)
                        const data = await postApi('/chat', {
                            message: `${scene.imagePrompt} ${imageUrl}`,
                            mode: 'animate',
                            provider: 'ollama',
                            vidModel: selectedVideoModel || videoModel || undefined,
                        });
                        // Backend returns media.video_url (NOT always media.videos[])
                        const rawVideoUrl = data?.media?.video_url ||
                            data?.media?.videos?.[0] ||
                            null;
                        if (rawVideoUrl) {
                            // Proxy the URL for correct Content-Type headers (WebM playback)
                            const proxiedVideoUrl = proxyVideoUrl(rawVideoUrl) || rawVideoUrl;
                            await patchApi(`/studio/videos/${projectId}/scenes/${scene.id}`, toScenePatch({
                                videoUrl: proxiedVideoUrl,
                                status: 'ready',
                            }));
                            setScenes((prev) => prev.map((s) => s.id === scene.id ? { ...s, videoUrl: proxiedVideoUrl, status: 'ready' } : s));
                        }
                        else {
                            // No video generated, mark scene as ready anyway (image only)
                            await patchApi(`/studio/videos/${projectId}/scenes/${scene.id}`, toScenePatch({
                                status: 'ready',
                            }));
                            setScenes((prev) => prev.map((s) => s.id === scene.id ? { ...s, status: 'ready' } : s));
                        }
                    }
                    catch (vidErr) {
                        console.error(`[CreatorStudioEditor] Failed to generate video for scene ${i + 1}:`, vidErr);
                        // Mark scene as ready anyway (fallback to image only)
                        try {
                            await patchApi(`/studio/videos/${projectId}/scenes/${scene.id}`, toScenePatch({ status: 'ready' }));
                            setScenes((prev) => prev.map((s) => s.id === scene.id ? { ...s, status: 'ready' } : s));
                        }
                        catch { }
                    }
                }
            }
            setLastSaved(new Date());
            setCurrentSceneIndex(0); // Go back to first scene
            console.log('[CreatorStudioEditor] Batch generation complete!');
            // Sync outline with actual scene data to keep them in sync
            await syncOutlineWithScenes();
            // Final refresh so UI shows all persisted videoUrl values
            await refreshScenes();
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Batch generation failed:', e);
        }
        finally {
            setIsBatchGenerating(false);
            setBatchProgress({ current: 0, total: 0, phase: 'scene' });
        }
    }, [storyOutline, projectId, postApi, patchApi, imageProvider, imageModel, selectedImageModel, imageSteps, imageCfg, projectWantsVideo, videoModel, selectedVideoModel, syncOutlineWithScenes, toScenePatch, refreshScenes, proxyVideoUrl]);
    // Load project and scenes
    useEffect(() => {
        async function loadData() {
            setLoading(true);
            setError(null);
            try {
                const [projectRes, scenesRes] = await Promise.all([
                    fetchApi(`/studio/videos/${projectId}`),
                    fetchApi(`/studio/videos/${projectId}/scenes`),
                ]);
                setProject(projectRes.video);
                setScenes(normalizeScenes(scenesRes.scenes));
                // Extract LLM model from project tags if not already set
                const tags = projectRes.video.tags || [];
                const llmTag = tags.find((t) => t.startsWith("llm:"));
                if (llmTag && !defaultLLMModel) {
                    const modelFromTag = llmTag.replace("llm:", "");
                    setSelectedLLMModel(modelFromTag);
                    setSettingsLLMModel(modelFromTag);
                }
            }
            catch (e) {
                setError(e.message || String(e));
            }
            finally {
                setLoading(false);
            }
        }
        loadData();
    }, [projectId, fetchApi, defaultLLMModel, normalizeScenes]);
    // Load available models and existing outline on mount
    useEffect(() => {
        fetchAvailableModels();
        loadStoryOutline();
    }, [fetchAvailableModels, loadStoryOutline]);
    // Detect whether the browser can play WebM videos
    useEffect(() => {
        try {
            const v = document.createElement("video");
            const ok = Boolean(v.canPlayType('video/webm; codecs="vp8, vorbis"') ||
                v.canPlayType('video/webm; codecs="vp9"') ||
                v.canPlayType("video/webm"));
            setCanPlayWebm(ok);
            console.log('[CreatorStudioEditor] WebM playback support:', ok);
        }
        catch {
            setCanPlayWebm(false);
        }
    }, []);
    // Auto-generate outline when project is newly created
    useEffect(() => {
        if (autoGenerateFirst &&
            !hasAutoGeneratedOutline &&
            !loading &&
            project &&
            !storyOutline &&
            !isGeneratingOutline &&
            selectedLLMModel // Wait until we have a model selected
        ) {
            console.log('[CreatorStudioEditor] Auto-generating story outline for new project');
            setHasAutoGeneratedOutline(true);
            generateStoryOutline();
        }
    }, [autoGenerateFirst, hasAutoGeneratedOutline, loading, project, storyOutline, isGeneratingOutline, selectedLLMModel, generateStoryOutline]);
    // Current scene
    const currentScene = scenes[currentSceneIndex] || null;
    // Extract visual style from project tags
    const getVisualStyle = useCallback(() => {
        if (!project)
            return "cinematic";
        const tags = project.tags || [];
        const visualTag = tags.find((t) => t.startsWith("visual:"));
        if (visualTag) {
            const style = visualTag.replace("visual:", "").replace(/_/g, " ");
            return style;
        }
        return "cinematic";
    }, [project]);
    // Extract tone from project tags
    const getTones = useCallback(() => {
        if (!project)
            return ["documentary"];
        const tags = project.tags || [];
        const tones = tags.filter((t) => t.startsWith("tone:")).map((t) => t.replace("tone:", "").replace(/_/g, " "));
        return tones.length > 0 ? tones : ["documentary"];
    }, [project]);
    // Generate AI-powered scene with better prompts
    const generateFirstSceneWithAI = useCallback(async () => {
        if (!project || isGeneratingScene)
            return;
        setIsGeneratingScene(true);
        try {
            let narration;
            let imagePrompt;
            let negativePrompt = "blurry, low quality, text, watermark, ugly, deformed, disfigured, bad anatomy, worst quality, low resolution, duplicate, clone, multiple people, two heads, two faces, split image, extra limbs";
            if (storyOutline && storyOutline.scenes && storyOutline.scenes.length > 0) {
                const outlineScene = storyOutline.scenes[0];
                narration = outlineScene.narration;
                imagePrompt = outlineScene.image_prompt;
                negativePrompt = outlineScene.negative_prompt || negativePrompt;
                console.log('[CreatorStudioEditor] Using story outline for first scene');
            }
            else {
                const visualStyle = getVisualStyle();
                const tones = getTones();
                const toneDesc = tones.join(", ");
                narration = `The story begins. ${project.logline || `Welcome to "${project.title}".`}`;
                imagePrompt = `${visualStyle} style, ${project.logline || project.title}, opening scene, establishing shot, ${toneDesc} mood, high quality, detailed, 4k, masterpiece`;
            }
            const data = await postApi(`/studio/videos/${projectId}/scenes`, {
                narration,
                imagePrompt,
                negativePrompt,
                durationSec: 5.0,
            });
            setScenes((prev) => [...prev, data.scene]);
            setCurrentSceneIndex(0);
            setLastSaved(new Date());
            console.log('[CreatorStudioEditor] Auto-generating image for first scene');
            generateImageForScene(data.scene.id, data.scene.imagePrompt);
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to create scene:', e);
            alert(`Failed to create scene: ${e.message}`);
        }
        finally {
            setIsGeneratingScene(false);
        }
    }, [project, projectId, isGeneratingScene, postApi, getVisualStyle, getTones, storyOutline, generateImageForScene]);
    // Auto-generate ALL scenes after outline is generated (batch generation)
    useEffect(() => {
        if (autoGenerateFirst &&
            !hasAutoTriggered &&
            !loading &&
            project &&
            storyOutline &&
            storyOutline.scenes &&
            storyOutline.scenes.length > 0 &&
            scenes.length === 0 &&
            !isGeneratingScene &&
            !isBatchGenerating) {
            console.log('[CreatorStudioEditor] Auto-generating ALL scenes from outline');
            setHasAutoTriggered(true);
            generateAllScenesFromOutline();
        }
    }, [autoGenerateFirst, hasAutoTriggered, loading, project, storyOutline, scenes.length, isGeneratingScene, isBatchGenerating, generateAllScenesFromOutline]);
    // Generate first scene (non-AI fallback)
    const generateFirstScene = useCallback(async () => {
        if (!project || isGeneratingScene)
            return;
        setIsGeneratingScene(true);
        try {
            const data = await postApi(`/studio/videos/${projectId}/scenes`, {
                narration: `Opening scene for "${project.title}"`,
                imagePrompt: `${project.logline || project.title}, cinematic, high quality, detailed`,
                negativePrompt: "blurry, low quality, text, watermark",
                durationSec: 5.0,
            });
            setScenes((prev) => [...prev, data.scene]);
            setCurrentSceneIndex(0);
            setLastSaved(new Date());
        }
        catch (e) {
            alert(`Failed to create scene: ${e.message}`);
        }
        finally {
            setIsGeneratingScene(false);
        }
    }, [project, projectId, isGeneratingScene, postApi]);
    // Generate next scene with AI-powered prompts (uses backend outline for reliability)
    const generateNextScene = useCallback(async () => {
        if (!project || isGeneratingScene)
            return;
        setIsGeneratingScene(true);
        try {
            const nextSceneIndex = scenes.length;
            // First, try to generate from outline via backend (reads outline from database - most reliable)
            try {
                const data = await postApi(`/studio/videos/${projectId}/scenes/generate-from-outline?scene_index=${nextSceneIndex}`, {});
                if (data.ok && data.scene) {
                    setScenes((prev) => [...prev, data.scene]);
                    setCurrentSceneIndex(nextSceneIndex);
                    setLastSaved(new Date());
                    console.log(`[CreatorStudioEditor] Generated scene ${nextSceneIndex + 1} from outline`);
                    generateImageForScene(data.scene.id, data.scene.imagePrompt);
                    // Sync outline with new scene
                    syncOutlineWithScenes();
                    return;
                }
            }
            catch (outlineErr) {
                // Outline not available or scene index out of range - try AI continuation
                console.log('[CreatorStudioEditor] No outline scene available, trying AI continuation:', outlineErr.message);
            }
            // Second: Try AI-powered continuation based on previous scenes
            if (scenes.length > 0) {
                try {
                    console.log('[CreatorStudioEditor] Generating AI continuation from previous context...');
                    const contData = await postApi(`/studio/videos/${projectId}/scenes/generate-continuation`, {});
                    if (contData.ok && contData.scene) {
                        setScenes((prev) => [...prev, contData.scene]);
                        setCurrentSceneIndex(nextSceneIndex);
                        setLastSaved(new Date());
                        console.log(`[CreatorStudioEditor] Generated scene ${nextSceneIndex + 1} via AI continuation`);
                        generateImageForScene(contData.scene.id, contData.scene.imagePrompt);
                        // Sync outline with new scene
                        syncOutlineWithScenes();
                        return;
                    }
                }
                catch (contErr) {
                    console.log('[CreatorStudioEditor] AI continuation failed, using fallback:', contErr.message);
                }
            }
            // Final fallback: Generate a scene based on project settings (no outline, no AI)
            const sceneNum = scenes.length + 1;
            const visualStyle = getVisualStyle();
            const tones = getTones();
            const toneDesc = tones.join(", ");
            const narration = `Scene ${sceneNum}. ${project.logline || `The story of "${project.title}" continues...`}`;
            const imagePrompt = `${visualStyle} style, ${project.logline || project.title}, scene ${sceneNum}, ${toneDesc} mood, high quality, detailed, 4k, masterpiece`;
            const negativePrompt = "blurry, low quality, text, watermark, ugly, deformed, disfigured, bad anatomy, worst quality, low resolution, duplicate, clone, multiple people, two heads, two faces, split image, extra limbs";
            const data = await postApi(`/studio/videos/${projectId}/scenes`, {
                narration,
                imagePrompt,
                negativePrompt,
                durationSec: 5.0,
            });
            setScenes((prev) => [...prev, data.scene]);
            setCurrentSceneIndex(scenes.length);
            setLastSaved(new Date());
            console.log('[CreatorStudioEditor] Generated scene with fallback content:', sceneNum);
            generateImageForScene(data.scene.id, data.scene.imagePrompt);
            // Sync outline with new scene
            syncOutlineWithScenes();
        }
        catch (e) {
            alert(`Failed to create scene: ${e.message}`);
        }
        finally {
            setIsGeneratingScene(false);
        }
    }, [project, projectId, scenes.length, isGeneratingScene, postApi, getVisualStyle, getTones, generateImageForScene, syncOutlineWithScenes]);
    // Generate next scene for TV Mode (uses backend outline for reliability)
    const generateNextForTVMode = useCallback(async () => {
        if (!project || isGeneratingScene)
            return null;
        try {
            const nextSceneIndex = scenes.length;
            // First, try to generate from outline via backend
            try {
                const data = await postApi(`/studio/videos/${projectId}/scenes/generate-from-outline?scene_index=${nextSceneIndex}`, {});
                if (data.ok && data.scene) {
                    setScenes((prev) => [...prev, data.scene]);
                    console.log(`[CreatorStudioEditor] TV Mode: Generated scene ${nextSceneIndex + 1} from outline`);
                    return sceneToTVScene(data.scene);
                }
            }
            catch (outlineErr) {
                console.log('[CreatorStudioEditor] TV Mode: No outline available, trying AI continuation');
            }
            // Second: Try AI-powered continuation based on previous scenes
            if (scenes.length > 0) {
                try {
                    console.log('[CreatorStudioEditor] TV Mode: Generating AI continuation from previous context...');
                    const contData = await postApi(`/studio/videos/${projectId}/scenes/generate-continuation`, {});
                    if (contData.ok && contData.scene) {
                        setScenes((prev) => [...prev, contData.scene]);
                        console.log(`[CreatorStudioEditor] TV Mode: Generated scene ${nextSceneIndex + 1} via AI continuation`);
                        return sceneToTVScene(contData.scene);
                    }
                }
                catch (contErr) {
                    console.log('[CreatorStudioEditor] TV Mode: AI continuation failed, using fallback:', contErr.message);
                }
            }
            // Final fallback: Generate scene based on project settings
            const sceneNum = scenes.length + 1;
            const visualStyle = getVisualStyle();
            const tones = getTones();
            const toneDesc = tones.join(", ");
            const narration = `Scene ${sceneNum}. ${project.logline || `The story of "${project.title}" continues...`}`;
            const imagePrompt = `${visualStyle} style, ${project.logline || project.title}, scene ${sceneNum}, ${toneDesc} mood, high quality, detailed, 4k, masterpiece`;
            const negativePrompt = "blurry, low quality, text, watermark, ugly, deformed, disfigured, bad anatomy, worst quality, low resolution, duplicate, clone, multiple people, two heads, two faces, split image, extra limbs";
            const data = await postApi(`/studio/videos/${projectId}/scenes`, {
                narration,
                imagePrompt,
                negativePrompt,
                durationSec: 5.0,
            });
            setScenes((prev) => [...prev, data.scene]);
            return sceneToTVScene(data.scene);
        }
        catch (e) {
            console.error('[CreatorStudioEditor] Failed to generate scene for TV mode:', e);
            return null;
        }
    }, [project, projectId, scenes.length, isGeneratingScene, postApi, getVisualStyle, getTones, sceneToTVScene]);
    // Ensure image for TV Mode scene
    const ensureImageForTVMode = useCallback((tvScene) => {
        const scene = scenes.find(s => s.idx === tvScene.idx);
        if (!scene)
            return;
        if (!tvScene.image_url && !tvScene.image) {
            generateImageForScene(scene.id, scene.imagePrompt).then(() => {
                const updatedScene = scenes.find(s => s.idx === tvScene.idx);
                if (updatedScene?.imageUrl) {
                    updateSceneImageByIdx(tvScene.idx, updatedScene.imageUrl);
                }
            });
        }
    }, [scenes, generateImageForScene, updateSceneImageByIdx]);
    // Status badge color
    const getStatusBadge = (status) => {
        switch (status) {
            case "draft":
                return { bg: "bg-amber-500/20", text: "text-amber-300", label: "Draft" };
            case "approved":
                return { bg: "bg-emerald-500/20", text: "text-emerald-300", label: "Finished" };
            case "in_review":
                return { bg: "bg-cyan-500/20", text: "text-cyan-300", label: "In Review" };
            case "archived":
                return { bg: "bg-slate-500/20", text: "text-slate-300", label: "Archived" };
            default:
                return { bg: "bg-slate-500/20", text: "text-slate-300", label: status };
        }
    };
    // Scene status indicator
    const SceneStatusIndicator = ({ status }) => {
        switch (status) {
            case 'generating':
                return (<div className="w-4 h-4 rounded-full bg-black/60 flex items-center justify-center">
            <Loader2 size={10} className="text-cyan-400 animate-spin"/>
          </div>);
            case 'ready':
                return null;
            case 'error':
                return (<div className="w-4 h-4 rounded-full bg-red-500/80 flex items-center justify-center">
            <AlertCircle size={10} className="text-white"/>
          </div>);
            case 'pending':
            default:
                return (<div className="w-4 h-4 rounded-full bg-black/60 flex items-center justify-center">
            <div className="w-2 h-2 rounded-full bg-white/40"/>
          </div>);
        }
    };
    // Loading state
    if (loading) {
        return (<div className="min-h-screen w-full bg-gradient-to-b from-black via-[#0a0a0f] to-[#0f0f18] text-white flex items-center justify-center">
        <div className="flex flex-col items-center gap-4">
          <Loader2 className="w-10 h-10 animate-spin text-cyan-400"/>
          <div className="text-white/60 text-sm">Loading project...</div>
        </div>
      </div>);
    }
    // Error state
    if (error || !project) {
        return (<div className="min-h-screen w-full bg-gradient-to-b from-black via-[#0a0a0f] to-[#0f0f18] text-white flex items-center justify-center">
        <div className="flex flex-col items-center gap-4 max-w-md text-center">
          <div className="w-16 h-16 rounded-2xl bg-red-500/10 border border-red-500/20 flex items-center justify-center mb-2">
            <AlertCircle size={28} className="text-red-400"/>
          </div>
          <div className="text-red-400 text-lg font-medium">Failed to load project</div>
          <div className="text-white/50 text-sm">{error || "Project not found"}</div>
          <button onClick={onExit} className="mt-4 px-6 py-2.5 bg-white/5 hover:bg-white/10 border border-white/10 rounded-xl transition-colors text-sm">
            ← Back to Studio
          </button>
        </div>
      </div>);
    }
    const statusBadge = getStatusBadge(project.status);
    return (<div className="min-h-screen w-full bg-gradient-to-b from-black via-[#0a0a0f] to-[#0f0f18] text-white flex flex-col">
      {/* Batch Generation Progress Overlay */}
      {isBatchGenerating && (<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/90 backdrop-blur-sm">
          <div className="bg-[#1a1a2e] border border-white/10 rounded-2xl p-8 max-w-md w-full mx-4 shadow-2xl">
            <div className="text-center">
              {/* Animated Icon */}
              <div className="mb-6 flex justify-center">
                <div className="relative">
                  <div className="w-20 h-20 rounded-full border-4 border-[#3ea6ff]/20"/>
                  <div className="absolute inset-0 w-20 h-20 rounded-full border-4 border-transparent border-t-[#3ea6ff] animate-spin" style={{ animationDuration: '1s' }}/>
                  <div className="absolute inset-0 flex items-center justify-center">
                    {batchProgress.phase === 'scene' ? (<Sparkles size={28} className="text-[#3ea6ff]"/>) : batchProgress.phase === 'image' ? (<ImageIcon size={28} className="text-[#3ea6ff]"/>) : (<Film size={28} className="text-[#3ea6ff]"/>)}
                  </div>
                </div>
              </div>

              {/* Title */}
              <h2 className="text-xl font-semibold text-white mb-2">
                {batchProgress.phase === 'scene' ? 'Creating Scenes' :
                batchProgress.phase === 'image' ? 'Generating Images' : 'Generating Videos'}
              </h2>

              {/* Progress Text */}
              <p className="text-white/60 mb-6">
                {batchProgress.phase === 'scene'
                ? `Building scene ${batchProgress.current} of ${batchProgress.total}...`
                : batchProgress.phase === 'image'
                    ? `Generating image ${batchProgress.current} of ${batchProgress.total}...`
                    : `Generating video ${batchProgress.current} of ${batchProgress.total}...`}
              </p>

              {/* Progress Bar */}
              <div className="mb-4">
                <div className="h-2 bg-white/10 rounded-full overflow-hidden">
                  <div className="h-full bg-gradient-to-r from-[#3ea6ff] to-[#6ec7ff] transition-all duration-300 ease-out" style={{
                width: batchProgress.total > 0
                    ? `${(batchProgress.current / batchProgress.total) * 100}%`
                    : '0%'
            }}/>
                </div>
                <div className="mt-2 text-xs text-white/40">
                  {batchProgress.phase === 'scene'
                ? (projectWantsVideo ? 'Phase 1/3: Creating scenes' : 'Phase 1/2: Creating scenes')
                : batchProgress.phase === 'image'
                    ? (projectWantsVideo ? 'Phase 2/3: Generating images' : 'Phase 2/2: Generating images')
                    : 'Phase 3/3: Generating videos'}
                </div>
              </div>

              {/* Tip */}
              <p className="text-xs text-white/30 mt-4">
                {batchProgress.phase === 'video'
                ? 'Video generation may take several minutes per scene'
                : 'This may take a few minutes depending on your hardware'}
              </p>
            </div>
          </div>
        </div>)}

      {/* Header - Compact & Cinematic */}
      <header className="flex items-center justify-between px-4 py-3 border-b border-white/5 bg-black/40 backdrop-blur-md">
        <div className="flex items-center gap-4">
          <button onClick={onExit} className="flex items-center gap-2 px-3 py-2 text-sm text-white/50 hover:text-white hover:bg-white/5 rounded-lg transition-all">
            <ArrowLeft size={16}/>
            <span className="hidden sm:inline">Back</span>
          </button>

          <div className="h-6 w-px bg-white/10"/>

          <div>
            <h1 className="text-base font-semibold text-white">{project.title}</h1>
            <div className="text-xs text-white/40">
              {scenes.length} scene{scenes.length !== 1 ? "s" : ""} • Creator Studio
            </div>
          </div>
        </div>

        <div className="flex items-center gap-2">
          {/* Status Badge */}
          <span className={`text-xs px-2.5 py-1 rounded-full font-medium ${statusBadge.bg} ${statusBadge.text}`}>
            {statusBadge.label}
          </span>

          {/* Save Indicator */}
          <div className="hidden sm:flex items-center gap-1.5 text-xs text-white/40 px-2">
            {isSaving ? (<>
                <Loader2 size={12} className="animate-spin"/>
                <span>Saving...</span>
              </>) : lastSaved ? (<>
                <Check size={12} className="text-emerald-400"/>
                <span>Saved</span>
              </>) : null}
          </div>

          {/* Project Settings Button */}
          <button onClick={openSettingsModal} className="p-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg transition-all" title="Project Settings">
            <Settings size={16} className="text-white/60"/>
          </button>

          {/* Story Outline Button */}
          <button onClick={() => setShowOutlinePanel(true)} className="flex items-center gap-2 px-3 py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg text-sm transition-all" title="Story Outline">
            <Wand2 size={14} className="text-cyan-400"/>
            <span className="hidden sm:inline">Outline</span>
          </button>

          {/* Export Button — opens the 2-step MP4 export wizard. */}
          <button type="button" onClick={() => setShowExportWizard(true)} className="flex items-center gap-2 px-3 py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg text-sm transition-all" title="Export project">
            <Download size={14}/>
            <span className="hidden sm:inline">Export</span>
          </button>
        </div>
      </header>

      {/* Export Wizard — mounts only while open. The wizard self-cleans
            its in-flight polling when closed (epoch guard). */}
      {showExportWizard && (<CreatorExportWizard open={showExportWizard} onClose={() => setShowExportWizard(false)} backendUrl={backendUrl} videoId={projectId} videoTitle={project?.title} scenes={scenes.map((s) => ({
                id: s.id,
                idx: s.idx,
                narration: s.narration || "",
                audioUrl: s.audioUrl || null,
            }))} disabledReason={scenes.length === 0
                ? "Add at least one scene before exporting."
                : scenes.some((s) => s.status !== "ready")
                    ? "All scenes must finish generating before export."
                    : null}/>)}

      {/* Scene Chips Rail - Like Play Story */}
      {scenes.length > 0 && (<div className="w-full overflow-x-auto scrollbar-hide border-b border-white/5 bg-black/20">
          <div className="flex gap-2 px-4 py-3 min-w-max">
            {scenes.map((scene, idx) => {
                const isActive = idx === currentSceneIndex;
                const hasImage = Boolean(scene.imageUrl);
                const hasVideo = Boolean(scene.videoUrl);
                const isHovered = hoveredSceneIdx === idx;
                const showDelete = isHovered && scenes.length > 1;
                return (<div key={scene.id} className="relative" onMouseEnter={() => setHoveredSceneIdx(idx)} onMouseLeave={() => setHoveredSceneIdx(null)}>
                  <button onClick={() => setCurrentSceneIndex(idx)} className={`
                      relative rounded-lg overflow-hidden transition-all duration-200
                      ${isActive
                        ? "ring-2 ring-cyan-400 ring-offset-2 ring-offset-black scale-105"
                        : hasVideo
                            ? "ring-1 ring-cyan-500/50 opacity-80 hover:opacity-100 hover:scale-102"
                            : "opacity-60 hover:opacity-100 hover:scale-102"}
                    `} type="button" title={`Scene ${idx + 1}${hasVideo ? ' (Video)' : ''}`}>
                    <div className="w-20 h-12 flex items-center justify-center bg-white/5">
                      {hasImage ? (<img src={scene.imageUrl} alt={`Scene ${idx + 1}`} className="w-full h-full object-cover"/>) : (<ImageIcon size={16} className="text-white/20"/>)}
                    </div>

                    {/* Subtle video indicator - small dot in corner */}
                    {hasVideo && (<div className="absolute top-1 right-1 w-2 h-2 bg-cyan-400 rounded-full shadow-sm shadow-cyan-400/50" title="Has video"/>)}

                    {/* Status indicator */}
                    <div className="absolute bottom-1 right-1">
                      <SceneStatusIndicator status={scene.status}/>
                    </div>

                    {/* Scene number */}
                    {!scene.status || scene.status === 'ready' ? (<div className="absolute bottom-1 left-1 text-[10px] bg-black/70 px-1.5 rounded font-medium">
                        {idx + 1}
                      </div>) : null}
                  </button>

                  {/* Delete button */}
                  {showDelete && (<button onClick={(e) => {
                            e.stopPropagation();
                            deleteScene(scene.id);
                        }} className="absolute -top-2 -right-2 w-5 h-5 rounded-full flex items-center justify-center transition-all transform hover:scale-110 bg-black/90 text-white/60 hover:text-white hover:bg-red-500 border border-white/10" type="button" title="Delete scene">
                      <X size={10}/>
                    </button>)}
                </div>);
            })}

            {/* Add Scene Chip */}
            <button onClick={generateNextScene} disabled={isGeneratingScene} className="w-20 h-12 rounded-lg border border-dashed border-white/20 hover:border-cyan-400/50 hover:bg-cyan-400/5 flex items-center justify-center transition-all disabled:opacity-40" title="Add scene">
              {isGeneratingScene ? (<Loader2 size={16} className="text-cyan-400 animate-spin"/>) : (<Plus size={16} className="text-white/40"/>)}
            </button>
          </div>
        </div>)}

      {/* Main Content */}
      {scenes.length === 0 ? (
        // Empty State - Cinematic
        <div className="flex-1 flex items-center justify-center p-8">
          <div className="max-w-md text-center">
            <div className="w-28 h-28 mx-auto mb-8 rounded-3xl bg-gradient-to-br from-cyan-500/20 via-blue-500/10 to-transparent border border-cyan-500/20 flex items-center justify-center">
              <ImageIcon size={48} className="text-cyan-400/60"/>
            </div>

            <h2 className="text-2xl font-semibold text-white mb-3">Create Your First Scene</h2>
            <p className="text-white/50 mb-8 leading-relaxed">
              Your project is ready. Generate a scene to start bringing your story to life with AI-powered visuals.
            </p>

            <button onClick={generateFirstScene} disabled={isGeneratingScene} className="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-cyan-500 to-blue-500 hover:from-cyan-400 hover:to-blue-400 disabled:opacity-50 disabled:cursor-not-allowed rounded-2xl text-base font-semibold shadow-lg shadow-cyan-500/25 transition-all">
              {isGeneratingScene ? (<>
                  <Loader2 size={20} className="animate-spin"/>
                  Generating...
                </>) : (<>
                  <Play size={20} fill="currentColor"/>
                  Generate First Scene
                </>)}
            </button>

            <p className="text-xs text-white/30 mt-6">
              Powered by AI • Based on your project settings
            </p>
          </div>
        </div>) : (
        // Preview + Actions - Cinematic Layout
        <div className="flex-1 flex flex-col">
          {/* Preview Panel - Dominant */}
          <div className="flex-1 relative overflow-hidden">
            {/* Background gradient */}
            <div className="absolute inset-0 bg-gradient-to-b from-transparent via-[#0a0a0f] to-[#0f0f18]"/>

            {/* Main preview area */}
            <div className="absolute inset-0 flex items-center justify-center p-6">
              {currentScene?.videoUrl ? (
            /* Video/Animation Preview - when scene has generated media */
            <div className="relative max-w-full max-h-full group">
                  {isAnimatedImageUrl(currentScene.videoUrl) ? (
                /* Animated WebP/GIF - render as <img> (some Comfy workflows output this) */
                <img src={proxyVideoUrl(currentScene.videoUrl) || currentScene.videoUrl} alt={`Scene ${currentSceneIndex + 1} animation`} className="max-h-[calc(100vh-320px)] max-w-full object-contain rounded-xl shadow-2xl shadow-black/50"/>) : isWebmUrl(currentScene.videoUrl) ? (
                /* WebM video - render as <video> */
                canPlayWebm ? (<video className="max-h-[calc(100vh-320px)] max-w-full object-contain rounded-xl shadow-2xl shadow-black/50" controls loop muted autoPlay playsInline preload="metadata" crossOrigin="anonymous" src={proxyVideoUrl(currentScene.videoUrl) || currentScene.videoUrl}/>) : (<div className="max-w-xl w-full bg-black/40 border border-white/10 rounded-xl p-6 text-center">
                        <div className="flex items-center justify-center gap-2 text-cyan-300 font-medium mb-2">
                          <Film size={16}/>
                          Video generated (WebM)
                        </div>
                        <div className="text-white/60 text-sm mb-4">
                          This browser cannot play WebM inline. Use Chrome/Edge/Firefox, or download the clip.
                        </div>
                        <a href={proxyVideoUrl(currentScene.videoUrl) || currentScene.videoUrl} target="_blank" rel="noreferrer" className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-white/10 hover:bg-white/15 border border-white/10 text-sm">
                          <Download size={14}/>
                          Open / Download WebM
                        </a>
                      </div>)) : (
                /* Unknown format fallback - try to display with download option */
                <div className="max-w-xl w-full bg-black/40 border border-white/10 rounded-xl p-6 text-center">
                      <div className="flex items-center justify-center gap-2 text-cyan-300 font-medium mb-2">
                        <Film size={16}/>
                        Generated media
                      </div>
                      <div className="text-white/60 text-sm mb-4">
                        This output format may not preview inline. Try opening in a new tab.
                      </div>
                      <a href={proxyVideoUrl(currentScene.videoUrl) || currentScene.videoUrl} target="_blank" rel="noreferrer" className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-white/10 hover:bg-white/15 border border-white/10 text-sm">
                        <Download size={14}/>
                        Open
                      </a>
                    </div>)}

                  {/* Top-right overlay controls - glass style */}
                  <div className="absolute top-3 right-3 flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
                    {/* More options */}
                    <button type="button" className="w-9 h-9 rounded-full bg-black/40 backdrop-blur-md border border-white/10 flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-all disabled:opacity-50 disabled:cursor-not-allowed" title="More options" onClick={() => {
                    setEditingScene(currentScene);
                    setEditNarration(currentScene.narration);
                    setEditImagePrompt(currentScene.imagePrompt);
                    setEditNegativePrompt(currentScene.negativePrompt || '');
                    setShowSceneEditor(true);
                }}>
                      <MoreHorizontal size={16}/>
                    </button>
                    {/* Regenerate video */}
                    <button type="button" onClick={() => generateVideoForScene(currentScene.id, currentScene.imageUrl, currentScene.imagePrompt)} disabled={isGeneratingVideo} className="w-9 h-9 rounded-full bg-black/40 backdrop-blur-md border border-white/10 flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-all disabled:opacity-50 disabled:cursor-not-allowed" title="Regenerate video">
                      <RefreshCw size={16} className={isGeneratingVideo ? 'animate-spin' : ''}/>
                    </button>
                    {/* Remove video */}
                    <button type="button" onClick={() => removeVideoForScene(currentScene.id)} disabled={isGeneratingVideo} className="w-9 h-9 rounded-full bg-red-500/30 backdrop-blur-md border border-red-500/30 flex items-center justify-center text-red-200 hover:text-white hover:bg-red-500/50 transition-all disabled:opacity-50 disabled:cursor-not-allowed" title="Remove video (keep image)">
                      <X size={16}/>
                    </button>
                  </div>

                  {/* Generating video overlay */}
                  {isGeneratingVideo && (<div className="absolute inset-0 flex items-center justify-center bg-black/70 backdrop-blur-sm rounded-xl">
                      <div className="flex flex-col items-center gap-3">
                        <Loader2 size={36} className="text-cyan-400 animate-spin"/>
                        <span className="text-white/70 text-sm">Generating video...</span>
                      </div>
                    </div>)}
                </div>) : currentScene?.imageUrl ? (
            /* Image Preview - when scene has image but no video */
            <div className="relative max-w-full max-h-full group">
                  <img src={currentScene.imageUrl} alt={`Scene ${currentSceneIndex + 1}`} className="max-h-[calc(100vh-320px)] max-w-full object-contain rounded-xl shadow-2xl shadow-black/50 transition-all duration-500"/>

                  {/* Top-right overlay controls - glass style */}
                  <div className="absolute top-3 right-3 flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
                    {/* More options */}
                    <button type="button" className="w-9 h-9 rounded-full bg-black/40 backdrop-blur-md border border-white/10 flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-all disabled:opacity-50 disabled:cursor-not-allowed" title="Edit scene" onClick={() => {
                    setEditingScene(currentScene);
                    setEditNarration(currentScene.narration);
                    setEditImagePrompt(currentScene.imagePrompt);
                    setEditNegativePrompt(currentScene.negativePrompt || '');
                    setShowSceneEditor(true);
                }}>
                      <MoreHorizontal size={16}/>
                    </button>
                    {/* Regenerate image */}
                    <button type="button" onClick={() => generateImageForScene(currentScene.id, currentScene.imagePrompt, true)} disabled={isGeneratingImage || isGeneratingVideo} className="w-9 h-9 rounded-full bg-black/40 backdrop-blur-md border border-white/10 flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-all disabled:opacity-50 disabled:cursor-not-allowed" title="Regenerate image">
                      <RefreshCw size={16} className={isGeneratingImage ? 'animate-spin' : ''}/>
                    </button>
                  </div>

                  {/* Bottom-right Make Video CTA - only show if project wants video and scene has no video yet */}
                  {projectWantsVideo && !currentScene.videoUrl && !isGeneratingImage && !isGeneratingVideo && (<div className="absolute bottom-4 right-4 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
                      <button type="button" onClick={() => generateVideoForScene(currentScene.id, currentScene.imageUrl, currentScene.imagePrompt)} className="flex items-center gap-2 px-4 py-2 bg-cyan-500/90 backdrop-blur-md border border-cyan-400/30 rounded-full text-white text-sm font-medium hover:bg-cyan-500 transition-all shadow-lg shadow-cyan-500/20" title="Convert to video">
                        <Film size={14}/>
                        Make Video
                      </button>
                    </div>)}

                  {/* Generating image overlay */}
                  {isGeneratingImage && (<div className="absolute inset-0 flex items-center justify-center bg-black/70 backdrop-blur-sm rounded-xl">
                      <div className="flex flex-col items-center gap-3">
                        <Loader2 size={36} className="text-cyan-400 animate-spin"/>
                        <span className="text-white/70 text-sm">Generating image...</span>
                      </div>
                    </div>)}

                  {/* Generating video overlay */}
                  {isGeneratingVideo && (<div className="absolute inset-0 flex items-center justify-center bg-black/70 backdrop-blur-sm rounded-xl">
                      <div className="flex flex-col items-center gap-3">
                        <Loader2 size={36} className="text-cyan-400 animate-spin"/>
                        <span className="text-white/70 text-sm">Converting to video...</span>
                        <span className="text-white/40 text-xs">This may take a few minutes</span>
                      </div>
                    </div>)}
                </div>) : (
            /* Empty state when no image */
            <div className="flex flex-col items-center justify-center text-center p-8">
                  {isGeneratingImage ? (<>
                      <Loader2 size={48} className="text-cyan-400 animate-spin mb-4"/>
                      <p className="text-white/60 text-sm">Generating image...</p>
                      {currentScene?.imagePrompt && (<p className="text-white/30 text-xs mt-2 max-w-md line-clamp-2">{currentScene.imagePrompt}</p>)}
                    </>) : (<>
                      <div className="w-20 h-20 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center mb-4">
                        <ImageIcon size={32} className="text-white/20"/>
                      </div>
                      <p className="text-white/40 text-sm mb-4">No image for this scene</p>
                      <button onClick={() => currentScene && generateImageForScene(currentScene.id, currentScene.imagePrompt)} className="flex items-center gap-2 px-5 py-2.5 bg-cyan-500 hover:bg-cyan-400 rounded-full text-white text-sm font-medium transition-colors" type="button">
                        Generate Image
                      </button>
                    </>)}
                </div>)}
            </div>

            {/* Narration subtitle overlay */}
            {currentScene?.narration && (<div className="absolute bottom-8 left-0 right-0 flex justify-center px-8 pointer-events-none">
                <div className="bg-black/80 backdrop-blur-md px-6 py-4 rounded-xl max-w-3xl shadow-xl border border-white/5">
                  <p className="text-base md:text-lg text-white leading-relaxed text-center">
                    {currentScene.narration}
                  </p>
                </div>
              </div>)}
          </div>

          {/* Action Bar - Like Play Story */}
          <div className="border-t border-white/5 bg-black/60 backdrop-blur-md">
            <div className="max-w-4xl mx-auto px-4 py-4">
              <div className="flex items-center justify-between gap-4">
                {/* Left: Playback controls */}
                <div className="flex items-center gap-2">
                  <button onClick={() => setCurrentSceneIndex((i) => Math.max(0, i - 1))} disabled={currentSceneIndex === 0} className="p-3 text-white/40 hover:text-white hover:bg-white/5 rounded-full transition-all disabled:opacity-30 disabled:cursor-not-allowed" type="button" title="Previous scene">
                    <SkipBack size={20}/>
                  </button>

                  <button onClick={() => setIsPlaying(!isPlaying)} className="p-4 bg-cyan-500 hover:bg-cyan-400 rounded-full transition-all shadow-lg shadow-cyan-500/25" type="button" title={isPlaying ? "Pause" : "Play"}>
                    {isPlaying ? <Pause size={24}/> : <Play size={24} fill="currentColor"/>}
                  </button>

                  <button onClick={() => setCurrentSceneIndex((i) => Math.min(scenes.length - 1, i + 1))} disabled={currentSceneIndex >= scenes.length - 1} className="p-3 text-white/40 hover:text-white hover:bg-white/5 rounded-full transition-all disabled:opacity-30 disabled:cursor-not-allowed" type="button" title="Next scene">
                    <SkipForward size={20}/>
                  </button>
                </div>

                {/* Center: Scene progress bar */}
                <div className="flex-1 mx-4 hidden sm:block">
                  <div className="flex gap-1">
                    {scenes.map((_, i) => (<button key={i} onClick={() => setCurrentSceneIndex(i)} className={`flex-1 h-1.5 rounded-full transition-all ${i === currentSceneIndex
                    ? 'bg-cyan-400'
                    : i < currentSceneIndex
                        ? 'bg-white/30'
                        : 'bg-white/10'}`} type="button" title={`Scene ${i + 1}`}/>))}
                  </div>
                </div>

                {/* Right: Actions */}
                <div className="flex items-center gap-2">
                  {/* Edit Scene Button */}
                  <button onClick={() => currentScene && openSceneEditor(currentScene)} disabled={!currentScene} className="flex items-center gap-2 px-4 py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-full text-sm transition-all disabled:opacity-40" title="Edit scene">
                    <Edit3 size={14}/>
                    <span className="hidden sm:inline">Edit</span>
                  </button>

                  {/* Generate Next Scene */}
                  <button onClick={generateNextScene} disabled={isGeneratingScene} className="flex items-center gap-2 px-4 py-2 bg-cyan-500/20 hover:bg-cyan-500/30 text-cyan-300 border border-cyan-500/30 rounded-full text-sm transition-all disabled:opacity-50" title="Generate next scene">
                    {isGeneratingScene ? (<>
                        <Loader2 size={14} className="animate-spin"/>
                        <span className="hidden sm:inline">Generating...</span>
                      </>) : (<>
                        <Plus size={14}/>
                        <span className="hidden sm:inline">Next Scene</span>
                      </>)}
                  </button>

                  {/* TV Mode */}
                  <button onClick={handleEnterTVMode} disabled={scenes.length === 0} className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-cyan-500/20 to-blue-500/20 hover:from-cyan-500/30 hover:to-blue-500/30 text-cyan-300 border border-cyan-500/30 rounded-full text-sm transition-all disabled:opacity-40" type="button" title="Watch in TV Mode">
                    <Monitor size={14}/>
                    <span className="hidden sm:inline">TV Mode</span>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>)}

      {/* Scene Editor Modal */}
      {showSceneEditor && editingScene && (<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
          <div className="absolute inset-0 bg-black/80 backdrop-blur-sm" onClick={() => setShowSceneEditor(false)}/>
          <div className="relative w-full max-w-2xl rounded-2xl border border-white/10 bg-[#0f0f18] shadow-2xl max-h-[90vh] overflow-y-auto">
            {/* Modal Header */}
            <div className="flex items-center justify-between p-5 border-b border-white/10">
              <div className="flex items-center gap-3">
                <div className="w-10 h-10 rounded-xl bg-cyan-500/20 flex items-center justify-center">
                  <Edit3 size={18} className="text-cyan-400"/>
                </div>
                <div>
                  <h2 className="text-lg font-semibold">Edit Scene {editingScene.idx + 1}</h2>
                  <p className="text-xs text-white/40">Update narration and prompts</p>
                </div>
              </div>
              <button onClick={() => setShowSceneEditor(false)} className="p-2 rounded-lg hover:bg-white/5 transition-colors">
                <X size={18} className="text-white/40"/>
              </button>
            </div>

            {/* Modal Content */}
            <div className="p-5 space-y-5">
              {/* Narration */}
              <div>
                <label className="flex items-center gap-2 text-sm font-medium text-white/70 mb-2">
                  <FileText size={14}/>
                  Narration
                </label>
                <textarea value={editNarration} onChange={(e) => setEditNarration(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white placeholder-white/30 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none resize-none transition-all" rows={3} placeholder="Enter narration text for this scene..."/>
              </div>

              {/* Image Prompt */}
              <div>
                <label className="flex items-center gap-2 text-sm font-medium text-white/70 mb-2">
                  <Sparkles size={14}/>
                  Image Prompt
                </label>
                <textarea value={editImagePrompt} onChange={(e) => setEditImagePrompt(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white placeholder-white/30 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none resize-none transition-all" rows={4} placeholder="Describe the visual elements for image generation..."/>
              </div>

              {/* Negative Prompt */}
              <div>
                <label className="text-sm font-medium text-white/70 mb-2 block">
                  Negative Prompt
                </label>
                <textarea value={editNegativePrompt} onChange={(e) => setEditNegativePrompt(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white placeholder-white/30 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none resize-none transition-all" rows={2} placeholder="Elements to avoid in the image..."/>
              </div>

              {/* Model Selection */}
              <div className="grid grid-cols-2 gap-4">
                <div>
                  <label className="flex items-center gap-2 text-sm font-medium text-white/70 mb-2">
                    <Settings size={14}/>
                    LLM Model
                  </label>
                  <select value={selectedLLMModel} onChange={(e) => setSelectedLLMModel(e.target.value)} className="w-full px-3 py-2.5 bg-black/40 border border-white/10 rounded-xl text-white focus:border-cyan-500/50 focus:outline-none transition-all">
                    <option value="">Default</option>
                    {availableLLMModels.map((m) => (<option key={m.id} value={m.id}>{m.name}</option>))}
                  </select>
                </div>

                <div>
                  <label className="flex items-center gap-2 text-sm font-medium text-white/70 mb-2">
                    <ImageIcon size={14}/>
                    Image Model
                  </label>
                  <select value={selectedImageModel} onChange={(e) => setSelectedImageModel(e.target.value)} className="w-full px-3 py-2.5 bg-black/40 border border-white/10 rounded-xl text-white focus:border-cyan-500/50 focus:outline-none transition-all">
                    <option value="">Default</option>
                    {availableImageModels.map((m) => (<option key={m.id} value={m.id}>{m.name}</option>))}
                  </select>
                </div>
              </div>
            </div>

            {/* Modal Footer */}
            <div className="flex items-center justify-between p-5 border-t border-white/10">
              <div className="flex items-center gap-2">
                {/* Regenerate Image button */}
                <button onClick={() => {
                generateImageForScene(editingScene.id, editImagePrompt, true);
                setShowSceneEditor(false);
            }} disabled={isGeneratingImage || isGeneratingVideo} className="flex items-center gap-2 px-4 py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-xl text-sm transition-all disabled:opacity-50">
                  <RefreshCw size={14}/>
                  Regenerate Image
                </button>

                {/* Make Video / Regenerate Video button */}
                {projectWantsVideo && editingScene.imageUrl && (<div className="flex items-center gap-2">
                    <button onClick={() => {
                    generateVideoForScene(editingScene.id, editingScene.imageUrl, editImagePrompt);
                    setShowSceneEditor(false);
                }} disabled={isGeneratingImage || isGeneratingVideo} className={[
                    "flex items-center gap-2 px-4 py-2 rounded-xl text-sm transition-all disabled:opacity-50",
                    editingScene.videoUrl
                        ? "bg-white/5 hover:bg-white/10 border border-white/10"
                        : "bg-cyan-500/20 hover:bg-cyan-500/30 border border-cyan-500/30 text-cyan-300"
                ].join(" ")}>
                      <Film size={14}/>
                      {editingScene.videoUrl ? 'Regenerate Video' : 'Make Video'}
                    </button>

                    {editingScene.videoUrl && (<button onClick={() => {
                        removeVideoForScene(editingScene.id);
                        setShowSceneEditor(false);
                    }} disabled={isGeneratingImage || isGeneratingVideo} className="flex items-center gap-2 px-4 py-2 bg-red-500/15 hover:bg-red-500/25 border border-red-500/25 rounded-xl text-sm text-red-200 transition-all disabled:opacity-50" title="Remove video and keep image">
                        <X size={14}/>
                        Remove Video
                      </button>)}
                  </div>)}
              </div>

              <div className="flex items-center gap-3">
                <button onClick={() => setShowSceneEditor(false)} className="px-4 py-2 text-sm text-white/50 hover:text-white transition-colors">
                  Cancel
                </button>
                <button onClick={saveSceneEdits} disabled={isSavingScene} className="flex items-center gap-2 px-5 py-2.5 bg-cyan-500 hover:bg-cyan-400 disabled:opacity-50 rounded-xl text-sm font-medium transition-all">
                  {isSavingScene ? (<>
                      <Loader2 size={14} className="animate-spin"/>
                      Saving...
                    </>) : (<>
                      <Save size={14}/>
                      Save Changes
                    </>)}
                </button>
              </div>
            </div>
          </div>
        </div>)}

      {/* Story Outline Panel */}
      {showOutlinePanel && (<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
          <div className="absolute inset-0 bg-black/80 backdrop-blur-sm" onClick={() => setShowOutlinePanel(false)}/>
          <div className="relative w-full max-w-3xl rounded-2xl border border-white/10 bg-[#0f0f18] shadow-2xl max-h-[90vh] overflow-y-auto">
            {/* Panel Header */}
            <div className="flex items-center justify-between p-5 border-b border-white/10">
              <div className="flex items-center gap-3">
                <div className="w-10 h-10 rounded-xl bg-cyan-500/20 flex items-center justify-center">
                  <Wand2 size={18} className="text-cyan-400"/>
                </div>
                <div>
                  <h2 className="text-lg font-semibold">Story Outline</h2>
                  <p className="text-xs text-white/40">AI-powered story structure</p>
                </div>
              </div>
              <div className="flex items-center gap-3">
                <button onClick={generateStoryOutline} disabled={isGeneratingOutline} className="flex items-center gap-2 px-4 py-2 bg-cyan-500 hover:bg-cyan-400 disabled:opacity-50 rounded-xl text-sm font-medium transition-all">
                  {isGeneratingOutline ? (<>
                      <Loader2 size={14} className="animate-spin"/>
                      Generating...
                    </>) : (<>
                      <Sparkles size={14}/>
                      {storyOutline ? "Regenerate" : "Generate"}
                    </>)}
                </button>
                <button onClick={() => setShowOutlinePanel(false)} className="p-2 rounded-lg hover:bg-white/5 transition-colors">
                  <X size={18} className="text-white/40"/>
                </button>
              </div>
            </div>

            {/* Panel Content */}
            <div className="p-5">
              {storyOutline ? (<div className="space-y-6">
                  {/* Story Arc */}
                  <div className="p-4 bg-black/30 rounded-xl border border-white/5">
                    <h3 className="text-sm font-semibold text-cyan-400 mb-3">Story Arc</h3>
                    <div className="grid grid-cols-5 gap-2 text-xs">
                      {['beginning', 'rising_action', 'climax', 'falling_action', 'resolution'].map((key, i) => (<div key={key} className="p-2.5 bg-white/5 rounded-lg">
                          <div className="text-white/40 mb-1 capitalize">{['Beginning', 'Rising', 'Climax', 'Falling', 'Resolution'][i]}</div>
                          <div className="text-white/80">{storyOutline.story_arc?.[key] || "—"}</div>
                        </div>))}
                    </div>
                  </div>

                  {/* Scene Outlines */}
                  <div>
                    <h3 className="text-sm font-semibold text-white/70 mb-3">
                      Scene Outlines ({storyOutline.scenes?.length || 0} scenes)
                    </h3>
                    <div className="space-y-3">
                      {storyOutline.scenes?.map((scene, idx) => {
                    const alreadyGenerated = scenes.length > idx;
                    return (<div key={idx} className={`p-4 rounded-xl border transition-all ${alreadyGenerated
                            ? "bg-emerald-500/10 border-emerald-500/30"
                            : "bg-black/30 border-white/10 hover:border-white/20"}`}>
                            <div className="flex items-start justify-between gap-4">
                              <div className="flex-1">
                                <div className="flex items-center gap-2 mb-1">
                                  <span className="text-sm font-medium text-white">
                                    Scene {scene.scene_number}: {scene.title}
                                  </span>
                                  {alreadyGenerated && (<span className="text-xs px-2 py-0.5 bg-emerald-500/20 text-emerald-400 rounded-full">
                                      Generated
                                    </span>)}
                                </div>
                                <p className="text-sm text-white/50 mb-2">{scene.description}</p>
                                <p className="text-xs text-white/30 italic">"{scene.narration}"</p>
                              </div>
                              {!alreadyGenerated && scenes.length === idx && (<button onClick={() => {
                                generateSceneFromOutline(idx);
                                setShowOutlinePanel(false);
                            }} disabled={isGeneratingScene} className="flex items-center gap-1.5 px-3 py-1.5 bg-cyan-500 hover:bg-cyan-400 disabled:opacity-50 rounded-lg text-xs font-medium transition-all">
                                  <Plus size={12}/>
                                  Generate
                                </button>)}
                            </div>
                          </div>);
                })}
                    </div>
                  </div>
                </div>) : (<div className="text-center py-16">
                  <div className="w-20 h-20 mx-auto rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center mb-6">
                    <Wand2 size={32} className="text-white/20"/>
                  </div>
                  <h3 className="text-lg font-medium text-white mb-2">No Outline Yet</h3>
                  <p className="text-white/40 mb-8 max-w-md mx-auto">
                    Generate an AI-powered story outline based on your project settings.
                    This creates a complete story arc with scene-by-scene planning.
                  </p>
                  <button onClick={generateStoryOutline} disabled={isGeneratingOutline} className="inline-flex items-center gap-3 px-8 py-4 bg-gradient-to-r from-cyan-500 to-blue-500 hover:from-cyan-400 hover:to-blue-400 disabled:opacity-50 rounded-2xl font-semibold shadow-lg shadow-cyan-500/25 transition-all">
                    {isGeneratingOutline ? (<>
                        <Loader2 size={20} className="animate-spin"/>
                        Generating Outline...
                      </>) : (<>
                        <Sparkles size={20}/>
                        Generate Story Outline
                      </>)}
                  </button>
                </div>)}
            </div>
          </div>
        </div>)}

      {/* Project Settings Modal */}
      {showSettingsModal && (<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
          <div className="absolute inset-0 bg-black/80 backdrop-blur-sm" onClick={() => setShowSettingsModal(false)}/>
          <div className="relative w-full max-w-2xl rounded-2xl border border-white/10 bg-[#0f0f18] shadow-2xl max-h-[90vh] overflow-y-auto">
            {/* Modal Header */}
            <div className="flex items-center justify-between p-5 border-b border-white/10 sticky top-0 bg-[#0f0f18] z-10">
              <div className="flex items-center gap-3">
                <div className="w-10 h-10 rounded-xl bg-cyan-500/20 flex items-center justify-center">
                  <Settings size={18} className="text-cyan-400"/>
                </div>
                <div>
                  <h2 className="text-lg font-semibold">Project Settings</h2>
                  <p className="text-xs text-white/40">Customize your project configuration</p>
                </div>
              </div>
              <button onClick={() => setShowSettingsModal(false)} className="p-2 rounded-lg hover:bg-white/5 transition-colors">
                <X size={18} className="text-white/40"/>
              </button>
            </div>

            {/* Modal Content */}
            <div className="p-5 space-y-6">
              {/* Title & Description */}
              <div className="space-y-4">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <FileText size={14}/>
                  Details
                </h3>

                <div>
                  <label className="block text-xs font-medium text-white/50 mb-2">Title</label>
                  <input type="text" value={settingsTitle} onChange={(e) => setSettingsTitle(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white placeholder-white/30 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none transition-all" placeholder="Project title"/>
                </div>

                <div>
                  <label className="block text-xs font-medium text-white/50 mb-2">Description</label>
                  <textarea value={settingsLogline} onChange={(e) => setSettingsLogline(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white placeholder-white/30 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none resize-none transition-all" rows={2} placeholder="A short description of your project..."/>
                </div>
              </div>

              {/* Format */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <Tv size={14}/>
                  Format
                </h3>
                <div className="grid grid-cols-3 gap-3">
                  <button onClick={() => setSettingsPlatform("youtube_16_9")} className={`p-4 rounded-xl border text-center transition-all ${settingsPlatform === "youtube_16_9"
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10"}`}>
                    <Tv size={24} className={`mx-auto mb-2 ${settingsPlatform === "youtube_16_9" ? "text-cyan-400" : "text-white/40"}`}/>
                    <div className="text-sm font-medium">YouTube Video</div>
                    <div className="text-xs text-white/40">16:9 Landscape</div>
                  </button>

                  <button onClick={() => setSettingsPlatform("shorts_9_16")} className={`p-4 rounded-xl border text-center transition-all ${settingsPlatform === "shorts_9_16"
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10"}`}>
                    <Smartphone size={24} className={`mx-auto mb-2 ${settingsPlatform === "shorts_9_16" ? "text-cyan-400" : "text-white/40"}`}/>
                    <div className="text-sm font-medium">YouTube Short</div>
                    <div className="text-xs text-white/40">9:16 Vertical</div>
                  </button>

                  <button onClick={() => setSettingsPlatform("slides_16_9")} className={`p-4 rounded-xl border text-center transition-all ${settingsPlatform === "slides_16_9"
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10"}`}>
                    <Presentation size={24} className={`mx-auto mb-2 ${settingsPlatform === "slides_16_9" ? "text-cyan-400" : "text-white/40"}`}/>
                    <div className="text-sm font-medium">Slides</div>
                    <div className="text-xs text-white/40">16:9 Presentation</div>
                  </button>
                </div>
              </div>

              {/* Image Generation Model */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <ImageIcon size={14}/>
                  Image Generation
                </h3>
                <div className="p-4 rounded-xl border border-white/10 bg-white/5">
                  <label className="block text-xs font-medium text-white/50 mb-2">Image Model</label>
                  <div className="relative">
                    <select value={settingsImageModel} onChange={(e) => setSettingsImageModel(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none transition-all appearance-none cursor-pointer" disabled={loadingModels}>
                      {loadingModels ? (<option value="">Loading models...</option>) : availableImageModels.length === 0 ? (<option value="">No models available</option>) : (availableImageModels.map((m) => (<option key={m.id} value={m.id}>{m.name}</option>)))}
                    </select>
                    <ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-white/40 pointer-events-none"/>
                  </div>
                  <p className="text-xs text-white/30 mt-2">Override the global image model for this project</p>
                </div>
              </div>

              {/* Video Generation Toggle */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <Film size={14}/>
                  Video Generation
                </h3>
                <div className={`p-4 rounded-xl border transition-all ${settingsEnableVideo
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10 cursor-pointer"}`} onClick={(e) => {
                // Only toggle if clicking on the toggle area, not on child elements like select
                if (e.target.tagName !== 'SELECT') {
                    if (!settingsEnableVideo)
                        setSettingsEnableVideo(true);
                }
            }}>
                  <div className="flex items-center justify-between">
                    <div className="flex items-center gap-3">
                      <div className={`w-10 h-10 rounded-lg flex items-center justify-center ${settingsEnableVideo ? "bg-cyan-500/30" : "bg-white/10"}`}>
                        <Film size={18} className={settingsEnableVideo ? "text-cyan-400" : "text-white/40"}/>
                      </div>
                      <div>
                        <div className="text-sm font-medium">Enable Video Generation</div>
                        <div className="text-xs text-white/40">
                          {settingsEnableVideo
                ? "Make Video button visible for each scene"
                : "Scenes will be static images only"}
                        </div>
                      </div>
                    </div>
                    <div className={`relative w-12 h-6 rounded-full transition-colors ${settingsEnableVideo ? "bg-cyan-500" : "bg-white/20"}`}>
                      <div className={`absolute top-1 w-4 h-4 rounded-full bg-white transition-transform ${settingsEnableVideo ? "translate-x-7" : "translate-x-1"}`}/>
                    </div>
                  </div>
                  {settingsEnableVideo && settingsPlatform === "slides_16_9" && (<div className="mt-3 p-2 bg-amber-500/10 border border-amber-500/30 rounded-lg text-xs text-amber-400">
                      Tip: Slides with video will create animated clips instead of static images with Ken Burns effect.
                    </div>)}
                  {/* Video Model Selector - shown when video is enabled */}
                  {settingsEnableVideo && (<div className="mt-4 pt-4 border-t border-white/10" onClick={(e) => e.stopPropagation()}>
                      <label className="block text-xs font-medium text-white/50 mb-2">Video Model</label>
                      <div className="relative">
                        <select value={settingsVideoModel} onChange={(e) => setSettingsVideoModel(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/25 focus:outline-none transition-all appearance-none cursor-pointer" disabled={loadingModels}>
                          {loadingModels ? (<option value="">Loading models...</option>) : availableVideoModels.length === 0 ? (<option value="">No video models available</option>) : (availableVideoModels.map((m) => (<option key={m.id} value={m.id}>{m.name}</option>)))}
                        </select>
                        <ChevronDown className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-white/40 pointer-events-none"/>
                      </div>
                      <p className="text-xs text-white/30 mt-2">Override the global video model for this project</p>
                    </div>)}
                  {/* Toggle OFF button when video is enabled */}
                  {settingsEnableVideo && (<button type="button" onClick={(e) => { e.stopPropagation(); setSettingsEnableVideo(false); }} className="mt-4 w-full px-4 py-2 text-xs text-white/50 hover:text-white/70 border border-white/10 rounded-lg hover:bg-white/5 transition-all">
                      Disable Video Generation
                    </button>)}
                </div>
              </div>

              {/* Intent */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400">Intent</h3>
                <div className="flex gap-2 flex-wrap">
                  {["Entertain", "Educate", "Inspire"].map((g) => (<button key={g} onClick={() => setSettingsGoal(g)} className={`px-4 py-2 rounded-full text-sm border transition-all ${settingsGoal === g
                    ? "bg-white text-black font-medium border-transparent"
                    : "bg-white/5 text-white/60 border-white/10 hover:bg-white/10 hover:text-white"}`}>
                      {g}
                    </button>))}
                </div>
              </div>

              {/* Episode Configuration */}
              <div className="grid grid-cols-2 gap-4">
                <div>
                  <label className="block text-xs font-medium text-white/50 mb-2">Scenes per Episode</label>
                  <div className="flex gap-2 flex-wrap">
                    {[4, 6, 8, 10, 12].map((count) => (<button key={count} onClick={() => setSettingsSceneCount(count)} className={`px-4 py-2 rounded-lg text-sm transition-all ${settingsSceneCount === count
                    ? "bg-cyan-500 text-white font-medium"
                    : "bg-white/5 text-white/60 hover:bg-white/10"}`}>
                        {count}
                      </button>))}
                  </div>
                  <p className="text-xs text-white/30 mt-1">
                    ~{settingsSceneCount * settingsSceneDuration}s total
                  </p>
                </div>

                <div>
                  <label className="block text-xs font-medium text-white/50 mb-2">Scene Duration</label>
                  <div className="flex gap-2 flex-wrap">
                    {[3, 5, 7, 10].map((dur) => (<button key={dur} onClick={() => setSettingsSceneDuration(dur)} className={`px-4 py-2 rounded-lg text-sm transition-all ${settingsSceneDuration === dur
                    ? "bg-cyan-500 text-white font-medium"
                    : "bg-white/5 text-white/60 hover:bg-white/10"}`}>
                        {dur}s
                      </button>))}
                  </div>
                </div>
              </div>

              {/* Visual Style */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <Palette size={14}/>
                  Visual Style
                </h3>
                <div className="grid grid-cols-3 gap-3">
                  <button onClick={() => setSettingsVisualStyle("Cinematic")} className={`p-3 rounded-xl border text-center transition-all ${settingsVisualStyle === "Cinematic"
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10"}`}>
                    <Camera size={20} className={`mx-auto mb-1.5 ${settingsVisualStyle === "Cinematic" ? "text-cyan-400" : "text-white/40"}`}/>
                    <div className="text-sm font-medium">Cinematic</div>
                    <div className="text-xs text-white/40">High fidelity</div>
                  </button>

                  <button onClick={() => setSettingsVisualStyle("Digital Art")} className={`p-3 rounded-xl border text-center transition-all ${settingsVisualStyle === "Digital Art"
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10"}`}>
                    <Palette size={20} className={`mx-auto mb-1.5 ${settingsVisualStyle === "Digital Art" ? "text-cyan-400" : "text-white/40"}`}/>
                    <div className="text-sm font-medium">Digital Art</div>
                    <div className="text-xs text-white/40">Stylized</div>
                  </button>

                  <button onClick={() => setSettingsVisualStyle("Anime")} className={`p-3 rounded-xl border text-center transition-all ${settingsVisualStyle === "Anime"
                ? "border-cyan-500 bg-cyan-500/10"
                : "border-white/10 bg-white/5 hover:bg-white/10"}`}>
                    <Star size={20} className={`mx-auto mb-1.5 ${settingsVisualStyle === "Anime" ? "text-cyan-400" : "text-white/40"}`}/>
                    <div className="text-sm font-medium">Anime</div>
                    <div className="text-xs text-white/40">Japanese style</div>
                  </button>
                </div>
              </div>

              {/* Mood & Tone */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400">Mood & Tone</h3>
                <div className="flex gap-2 flex-wrap">
                  {["Documentary", "Dramatic", "Calm", "Upbeat", "Dark"].map((t) => (<button key={t} onClick={() => toggleSettingsTone(t)} className={`px-4 py-2 rounded-full text-sm border transition-all ${settingsTones.includes(t)
                    ? "bg-white text-black font-medium border-transparent"
                    : "bg-white/5 text-white/60 border-white/10 hover:bg-white/10 hover:text-white"}`}>
                      {t}
                    </button>))}
                </div>
              </div>

              {/* AI Story Model */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <Sparkles size={14}/>
                  AI Story Model
                </h3>
                <p className="text-xs text-white/40">Select the AI model for generating outlines and narration</p>
                <select value={settingsLLMModel} onChange={(e) => setSettingsLLMModel(e.target.value)} className="w-full px-4 py-3 bg-black/40 border border-white/10 rounded-xl text-white focus:border-cyan-500/50 focus:outline-none transition-all appearance-none cursor-pointer">
                  {availableLLMModels.length === 0 ? (<option value="">No models available</option>) : (availableLLMModels.map((m) => (<option key={m.id} value={m.id}>
                        {m.name}
                      </option>)))}
                </select>
                {availableLLMModels.length === 0 && (<p className="text-xs text-red-400">
                    No Ollama models found. Make sure Ollama is running with at least one model.
                  </p>)}
              </div>

              {/* Checks */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <Shield size={14}/>
                  Checks
                </h3>
                <div className="bg-black/30 rounded-xl border border-white/10 divide-y divide-white/10">
                  <label className="flex items-center justify-between p-4 cursor-pointer hover:bg-white/5 transition-colors">
                    <div className="flex items-center gap-3">
                      <Lock size={16} className="text-white/40"/>
                      <div>
                        <div className="text-sm font-medium">Consistency Lock</div>
                        <div className="text-xs text-white/40">Keep characters stable across scenes</div>
                      </div>
                    </div>
                    <input type="checkbox" checked={settingsLockIdentity} onChange={(e) => setSettingsLockIdentity(e.target.checked)} className="w-5 h-5 accent-cyan-500"/>
                  </label>

                  <label className="flex items-center justify-between p-4 cursor-pointer hover:bg-white/5 transition-colors">
                    <div className="flex items-center gap-3">
                      <Shield size={16} className="text-white/40"/>
                      <div>
                        <div className="text-sm font-medium">Safe for Work (SFW)</div>
                        <div className="text-xs text-white/40">Filter explicit content</div>
                      </div>
                    </div>
                    <input type="checkbox" checked={settingsContentRating === "sfw"} onChange={(e) => setSettingsContentRating(e.target.checked ? "sfw" : "mature")} className="w-5 h-5 accent-cyan-500"/>
                  </label>
                </div>

                {settingsContentRating === "mature" && (<div className="p-3 bg-purple-500/10 border border-purple-500/30 rounded-xl text-sm">
                    <span className="font-medium text-purple-400">Mature Mode Enabled</span>
                    <span className="text-white/50 ml-2">- This project may generate explicit content.</span>
                  </div>)}
              </div>

              {/* Generation Parameters */}
              <div className="space-y-3">
                <h3 className="text-sm font-semibold text-cyan-400 flex items-center gap-2">
                  <Sliders size={14}/>
                  Generation Parameters
                </h3>
                <p className="text-xs text-white/40">
                  Customize generation defaults for images & videos. These override model presets.
                </p>
                <CreatorStudioSettings value={genParams} onChange={setGenParams}/>
              </div>
            </div>

            {/* Modal Footer */}
            <div className="flex items-center justify-end gap-3 p-5 border-t border-white/10 sticky bottom-0 bg-[#0f0f18]">
              <button onClick={() => setShowSettingsModal(false)} className="px-4 py-2 text-sm text-white/50 hover:text-white transition-colors">
                Cancel
              </button>
              <button onClick={saveProjectSettings} disabled={isSavingSettings || !settingsTitle.trim()} className="flex items-center gap-2 px-5 py-2.5 bg-cyan-500 hover:bg-cyan-400 disabled:opacity-50 rounded-xl text-sm font-medium transition-all">
                {isSavingSettings ? (<>
                    <Loader2 size={14} className="animate-spin"/>
                    Saving...
                  </>) : (<>
                    <Save size={14}/>
                    Save Settings
                  </>)}
              </button>
            </div>
          </div>
        </div>)}

      {/* TV Mode Overlay */}
      {tvModeActive && (<TVModeContainer onGenerateNext={generateNextForTVMode} onEnsureImage={ensureImageForTVMode} onSyncOutline={syncOutlineWithScenes}/>)}

      {/* Custom scrollbar hide */}
      <style>{`
        .scrollbar-hide::-webkit-scrollbar { display: none; }
        .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; }
        .line-clamp-2 {
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
          overflow: hidden;
        }
      `}</style>
    </div>);
}
export default CreatorStudioEditor;
