import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from "react"; import { Script, Knobs, Scene, PodcastMode } from "../types"; import { podcastApi } from "../../../services/podcastApi"; import { getApiUrl } from "../../../api/client"; interface ScriptEditorContextType { // State script: Script | null; loading: boolean; error: string | null; podcastMode: PodcastMode; approvingSceneId: string | null; generatingAudioId: string | null; showScriptFormatInfo: boolean; combiningAudio: boolean; scriptTab: "audio" | "video"; combinedAudioResult: { url: string; filename: string; duration: number; sceneCount: number } | null; generatingBatchAudio: boolean; batchAudioProgress: { completed: number; total: number } | null; generatingChartId: string | null; // B-roll: generating chart preview // Computed activeScript: Script | null; allApproved: boolean | null; approvedCount: number; totalScenes: number; allScenesHaveAudio: boolean | null; scenesWithAudio: number; allScenesHaveAudioAndImages: boolean | null; needsAudioGeneration: boolean | null; scenesWithCharts: number; // B-roll: count of scenes with chart data // Setters for UI state setScript: React.Dispatch>; setLoading: React.Dispatch>; setError: React.Dispatch>; setApprovingSceneId: React.Dispatch>; setGeneratingAudioId: React.Dispatch>; setShowScriptFormatInfo: React.Dispatch>; setCombiningAudio: React.Dispatch>; setScriptTab: React.Dispatch>; setCombinedAudioResult: React.Dispatch>; setGeneratingBatchAudio: React.Dispatch>; setBatchAudioProgress: React.Dispatch>; setGeneratingChartId: React.Dispatch>; // Actions updateScene: (updated: Scene) => void; approveScene: (sceneId: string) => Promise; deleteScene: (sceneId: string) => void; generateAllAudio: () => Promise; combineAudio: () => Promise; emitScriptChange: (next: Script) => void; // B-roll actions generateChartPreviews: () => Promise; regenerateChart: (sceneId: string) => Promise; removeChart: (sceneId: string) => void; } const ScriptEditorContext = createContext(undefined); const toUsablePreviewUrl = (previewUrl?: string): string | undefined => { if (!previewUrl) return undefined; if (/^https?:\/\//i.test(previewUrl)) return previewUrl; const cleanPath = previewUrl.startsWith("/") ? previewUrl : `/${previewUrl}`; return `${getApiUrl()}${cleanPath}`; }; interface ScriptEditorProviderProps { children: ReactNode; projectId: string; idea: string; rawResearch: any; knobs: Knobs; speakers: number; durationMinutes: number; initialScript: Script | null; initialAudioScript?: Script | null; initialVideoScript?: Script | null; podcastMode?: PodcastMode; analysis?: any; outline?: any; onScriptChange: (script: Script) => void; onError: (message: string) => void; } export const ScriptEditorProvider: React.FC = ({ children, projectId, idea, rawResearch, knobs, speakers, durationMinutes, initialScript, initialAudioScript, initialVideoScript, podcastMode = "video_only", analysis, outline, onScriptChange, onError, }) => { // Core state const [script, setScript] = useState