'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import React, { useEffect, useMemo, useState } from 'react';
import { twMerge } from 'tailwind-merge';

import ImageWithFallback from '@/components/image/ImageWithFallback';
import { toast } from '@/components/toast/Toast';
import { useApiClient } from '@/lib/apiClient';

interface VideoGenStep {
  id: string;
  name: string;
  status: 'pending' | 'running' | 'completed' | 'failed';
  description: string;
  output?: any;
}

interface GeneratedImage {
  id: string;
  prompt: string;
  status: string;
  raw_image_url?: string;
  min_image_url?: string;
  scene_index?: number;
}

interface GeneratedVideo {
  id: string;
  status: string;
  video_url?: string;
  scene_index?: number;
}

interface CustomReference {
  id: string;
  name: string;
  status: 'not_ready' | 'queued' | 'in_progress' | 'completed' | 'failed';
  created_at: string;
  fail_reason?: string;
  thumbnail_url?: string;
}

const VideoGenClient: React.FC = () => {
  const apiClient = useApiClient();
  const queryClient = useQueryClient();
  const [clipId, setClipId] = useState('');
  const [prompt, setPrompt] = useState('');
  const [workspaceId, setWorkspaceId] = useState('');
  const [isSceneScriptExpanded, setIsSceneScriptExpanded] = useState(false);
  const [currentImageIndex, setCurrentImageIndex] = useState(0);
  const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
  const [customReferenceId, setCustomReferenceId] = useState('');
  const [imageUrl, setImageUrl] = useState('');
  const [activeTab, setActiveTab] = useState<'generate' | 'reference' | 'load'>(
    'generate'
  );

  const [referenceName, setReferenceName] = useState('');
  const [referenceImages, setReferenceImages] = useState<string[]>(['']);
  const [createdReferenceId, setCreatedReferenceId] = useState('');
  const [shownCompletionToast, setShownCompletionToast] = useState(false);
  const [loadWorkspaceId, setLoadWorkspaceId] = useState('');
  const [selectedImageIds, setSelectedImageIds] = useState<Set<string>>(
    new Set()
  );
  const [selectedVideoIds, setSelectedVideoIds] = useState<Set<string>>(
    new Set()
  );
  const [scenePrompts, setScenePrompts] = useState<string[]>([]);

  // Helper function to extract error messages from API responses
  const extractErrorMessage = (error: any, fallback: string) => {
    if (error?.response?.data) {
      const data = error.response.data;
      if (typeof data.detail === 'string') {
        return data.detail;
      } else if (Array.isArray(data.detail)) {
        // Handle Pydantic validation errors
        return data.detail.map((err: any) => err.msg || err).join(', ');
      } else if (data.message) {
        return data.message;
      }
    } else if (error?.message) {
      return error.message;
    }
    return fallback;
  };

  const [steps, setSteps] = useState<VideoGenStep[]>([
    {
      id: 'scene-generation',
      name: 'Video Scene Generation',
      status: 'pending',
      description: 'Video scene is the blueprint of video gen based on lyrics',
    },
    {
      id: 'image-generation',
      name: 'Image Generation',
      status: 'pending',
      description:
        'Video scene passed to image gen with user sourced character consistency',
    },
    {
      id: 'video-generation',
      name: 'Video Generation',
      status: 'pending',
      description: 'Images passed to video gen',
    },
    {
      id: 'video-concatenation',
      name: 'Video Concatenation',
      status: 'pending',
      description: 'Combine generated videos into final output',
    },
  ]);

  // Create workspace mutation (now only creates workspace)
  const createWorkspaceMutation = useMutation<any, any, void>({
    mutationFn: async () => {
      const response = await apiClient.POST('/api/video_gen/generate_video', {
        body: {
          clip_id: clipId,
          type: 'soul_video',
          prompt: prompt || undefined,
          custom_reference_id: customReferenceId || undefined,
          image_url: imageUrl || undefined,
        },
      });

      if ((response as any).error) {
        const apiError = (response as any).error;
        const error = new Error(
          apiError.detail || apiError.message || 'API request failed'
        );
        (error as any).response = { data: apiError };
        throw error;
      }

      return response;
    },
    onSuccess: (data) => {
      if (data.data?.video_workspace_id) {
        setWorkspaceId(data.data.video_workspace_id);
        toast({
          title: 'Workspace Created',
          description:
            'Video workspace created successfully. You can now generate scene scripts.',
          status: 'success',
          duration: 4000,
          isClosable: true,
        });
      }
    },
    onError: (error: any) => {
      const errorMessage = extractErrorMessage(
        error,
        'Workspace creation failed'
      );
      toast({
        title: 'Workspace Creation Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Scene script generation mutation
  const generateSceneScriptMutation = useMutation<any, any, boolean>({
    mutationFn: async (regenerate = false) => {
      // Immediately set running state before API call
      setSteps((prev) =>
        prev.map((step) =>
          step.id === 'scene-generation'
            ? {
                ...step,
                status: 'running',
                output: regenerate ? undefined : step.output, // Clear output only when regenerating
                description: regenerate
                  ? 'Regenerating scene script...'
                  : 'Generating scene script...',
              }
            : step
        )
      );

      // If regenerating, also reset state
      if (regenerate) {
        // Reset current indices
        setCurrentImageIndex(0);
        setCurrentVideoIndex(0);
        // Clear image selection since we're regenerating
        setSelectedImageIds(new Set());
        // Clear video selection since we're regenerating
        setSelectedVideoIds(new Set());
        // Reset scene prompts so they'll be reinitialized with new scene script
        setScenePrompts([]);
        // Note: We'll let the workspace polling handle the data reset
      }

      const response = await apiClient.POST(
        '/api/video_gen/generate_scene_script',
        {
          body: {
            clip_id: clipId,
            video_workspace_id: workspaceId,
            regenerate: regenerate,
          },
        }
      );

      if ((response as any).error) {
        const apiError = (response as any).error;
        const error = new Error(
          apiError.detail ||
            apiError.message ||
            'Scene script generation failed'
        );
        (error as any).response = { data: apiError };
        throw error;
      }

      return { response, wasRegenerate: regenerate };
    },
    onSuccess: async (data) => {
      const { wasRegenerate } = data;

      // Force refetch workspace data to get the updated scene script immediately
      await queryClient.refetchQueries({
        queryKey: ['workspace', workspaceId],
        exact: true,
      });

      toast({
        title: wasRegenerate
          ? 'Scene Script Regenerated'
          : 'Scene Script Generated',
        description: wasRegenerate
          ? 'Scene script has been regenerated. All subsequent steps have been reset.'
          : 'Scene script has been generated successfully.',
        status: 'success',
        duration: 4000,
        isClosable: true,
      });
    },
    onError: (error: any) => {
      const errorMessage = extractErrorMessage(
        error,
        'Scene script generation failed'
      );
      toast({
        title: 'Scene Script Generation Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Soul images generation mutation
  const generateSoulImagesMutation = useMutation<any, any, boolean>({
    mutationFn: async (regenerate = false) => {
      // If regenerating, immediately reset state before API call
      if (regenerate) {
        setCurrentImageIndex(0);
        setCurrentVideoIndex(0);
        // Clear image selection since we're regenerating
        setSelectedImageIds(new Set());
        // Clear video selection since we're regenerating
        setSelectedVideoIds(new Set());
        // Reset the completion toast flag since we're starting over
        setShownCompletionToast(false);
      }

      const response = await apiClient.POST(
        '/api/video_gen/higgsfield/start_soul_images',
        {
          params: {
            query: {
              video_workspace_id: workspaceId,
              ...(customReferenceId && {
                custom_reference_id: customReferenceId,
              }),
              ...(imageUrl && { image_url: imageUrl }),
            },
          },
        }
      );

      if ((response as any).error) {
        const apiError = (response as any).error;
        const error = new Error(
          apiError.detail || apiError.message || 'Soul image generation failed'
        );
        (error as any).response = { data: apiError };
        throw error;
      }

      return { response, wasRegenerate: regenerate };
    },
    onSuccess: (data) => {
      const { wasRegenerate } = data;
      toast({
        title: wasRegenerate
          ? 'Soul Images Regenerated'
          : 'Soul Images Started',
        description: wasRegenerate
          ? 'Soul image generation has been restarted. Videos and final video have been reset.'
          : 'Soul image generation has been started.',
        status: 'success',
        duration: 4000,
        isClosable: true,
      });
    },
    onError: (error: any) => {
      const errorMessage = extractErrorMessage(
        error,
        'Soul image generation failed'
      );
      toast({
        title: 'Soul Image Generation Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Regenerate specific scene image mutation
  const regenerateSceneImageMutation = useMutation<
    any,
    any,
    { sceneIndex: number }
  >({
    mutationFn: async ({ sceneIndex }) => {
      const response = await apiClient.POST(
        '/api/video_gen/higgsfield/generate_image',
        {
          params: {
            query: {
              video_workspace_id: workspaceId,
              ...(customReferenceId && {
                custom_reference_id: customReferenceId,
              }),
              ...(imageUrl && { image_url: imageUrl }),
              scene_index: sceneIndex,
              prompt: scenePrompts[sceneIndex] || prompt,
            },
          },
        }
      );

      if ((response as any).error) {
        const apiError = (response as any).error;
        const error = new Error(
          apiError.detail ||
            apiError.message ||
            'Scene image regeneration failed'
        );
        (error as any).response = { data: apiError };
        throw error;
      }

      return { response, sceneIndex };
    },
    onSuccess: (data) => {
      const { sceneIndex } = data;
      toast({
        title: 'Scene Image Regenerated',
        description: `Scene ${sceneIndex + 1} image has been regenerated.`,
        status: 'success',
        duration: 4000,
        isClosable: true,
      });

      // Invalidate and refetch images query to get the updated image status
      queryClient.invalidateQueries({
        queryKey: ['images', workspaceId],
      });

      // Force immediate refetch to start polling for the new image
      queryClient.refetchQueries({
        queryKey: ['images', workspaceId],
        exact: true,
      });
    },
    onError: (error: any) => {
      const errorMessage = extractErrorMessage(
        error,
        'Scene image regeneration failed'
      );
      toast({
        title: 'Scene Image Regeneration Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Video generation mutation
  const generateVideosMutation = useMutation<
    any,
    any,
    { imageIds: string[]; regenerate?: boolean }
  >({
    mutationFn: async ({ imageIds, regenerate = false }) => {
      // If regenerating, immediately reset state before API call
      if (regenerate) {
        setCurrentVideoIndex(0);
        setShownCompletionToast(false);
      }

      const response = await apiClient.POST(
        '/api/video_gen/higgsfield/start_video_generation',
        {
          body: imageIds,
        }
      );

      if ((response as any).error) {
        const apiError = (response as any).error;
        const error = new Error(
          apiError.detail || apiError.message || 'Video generation failed'
        );
        (error as any).response = { data: apiError };
        throw error;
      }

      return { response, wasRegenerate: regenerate };
    },
    onSuccess: (data) => {
      const { wasRegenerate } = data;
      toast({
        title: wasRegenerate
          ? 'Video Generation Restarted'
          : 'Video Generation Started',
        description: wasRegenerate
          ? 'Video generation has been restarted. Final video has been reset.'
          : 'Video generation from images has been started.',
        status: 'success',
        duration: 4000,
        isClosable: true,
      });
    },
    onError: (error: any) => {
      const errorMessage = extractErrorMessage(
        error,
        'Video generation failed'
      );
      toast({
        title: 'Video Generation Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Concatenation mutation
  const concatenateVideosMutation = useMutation<
    any,
    any,
    { videoIds: string[]; regenerate?: boolean }
  >({
    mutationFn: async ({ videoIds, regenerate = false }) => {
      // Immediately update the step to show it's running
      setSteps((prev) =>
        prev.map((step) =>
          step.id === 'video-concatenation'
            ? {
                ...step,
                status: 'running',
                description: regenerate
                  ? 'Regenerating final video...'
                  : 'Concatenating videos...',
              }
            : step
        )
      );

      // If regenerating, immediately reset completion state
      if (regenerate) {
        setShownCompletionToast(false);
      }

      const response = await apiClient.POST(
        '/api/video_gen/higgsfield/start_concatenation',
        {
          params: {
            query: {
              video_workspace_id: workspaceId,
            },
          },
          body: videoIds,
        }
      );

      if ((response as any).error) {
        const apiError = (response as any).error;
        const error = new Error(
          apiError.detail || apiError.message || 'Video concatenation failed'
        );
        (error as any).response = { data: apiError };
        throw error;
      }

      return { response, wasRegenerate: regenerate };
    },
    onSuccess: (data) => {
      const { wasRegenerate } = data;
      toast({
        title: wasRegenerate
          ? 'Video Concatenation Restarted'
          : 'Video Concatenation Started',
        description: wasRegenerate
          ? 'Video concatenation has been restarted.'
          : 'Video concatenation has been started.',
        status: 'success',
        duration: 4000,
        isClosable: true,
      });
    },
    onError: (error: any) => {
      const errorMessage = extractErrorMessage(
        error,
        'Video concatenation failed'
      );

      // Reset the step status on error
      setSteps((prev) =>
        prev.map((step) =>
          step.id === 'video-concatenation'
            ? {
                ...step,
                status: videoStats.completed > 0 ? 'pending' : 'pending',
                description:
                  videoStats.completed > 0
                    ? 'Ready to concatenate videos'
                    : 'Generate videos first',
              }
            : step
        )
      );

      toast({
        title: 'Video Concatenation Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Custom reference creation mutation
  const createCustomReferenceMutation = useMutation<any, any, void>({
    mutationFn: async () => {
      const filteredImages = referenceImages.filter((img) => img.trim());
      if (filteredImages.length === 0 || !referenceName.trim()) {
        throw new Error('Name and at least one image URL are required');
      }

      const response = await apiClient.POST(
        '/api/video_gen/higgsfield/custom_reference',
        {
          body: {
            name: referenceName.trim(),
            input_images: filteredImages,
          },
        }
      );
      return response;
    },
    onSuccess: (data) => {
      if (data.data) {
        setCreatedReferenceId(data.data.id);
        setCustomReferenceId(data.data.id); // Auto-fill for convenience

        // Show success toast
        toast({
          title: 'Custom Reference Created',
          description:
            'Your custom reference has been created and is being processed. You can now use it for video generation.',
          status: 'success',
          duration: 4000,
          isClosable: true,
        });
      }
    },
    onError: (error: any) => {
      console.error('Custom reference creation error:', error);
      const errorMessage = extractErrorMessage(
        error,
        'Failed to create custom reference'
      );

      // Show error toast
      toast({
        title: 'Custom Reference Creation Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
      });
    },
  });

  // Load existing workspace mutation
  const loadWorkspaceMutation = useMutation<any, any, string>({
    mutationFn: async (workspaceIdToLoad: string) => {
      if (!workspaceIdToLoad.trim()) {
        throw new Error('Workspace ID is required');
      }

      const response = await apiClient.GET('/api/video_gen/video_workspace', {
        params: { query: { video_workspace_id: workspaceIdToLoad.trim() } },
      });
      return response.data;
    },
    onSuccess: (data) => {
      if (data) {
        // Set the workspace data
        setWorkspaceId(data.id);
        if (data.clip_id) {
          setClipId(data.clip_id);
        }
        setPrompt(data.prompt || '');

        // Set reference data if available
        if (data.custom_reference_id && data.custom_reference_id.trim()) {
          setCustomReferenceId(data.custom_reference_id);
        }
        if (data.image_url && data.image_url.trim()) {
          setImageUrl(data.image_url);
        }

        // Clear the load input
        setLoadWorkspaceId('');

        // Show success toast
        toast({
          title: 'Workspace Loaded',
          description: `Successfully loaded workspace ${data.id}`,
          status: 'success',
          duration: 4000,
          isClosable: true,
        });

        // Invalidate queries to refresh data
        queryClient.invalidateQueries({ queryKey: ['workspace', data.id] });
        queryClient.invalidateQueries({
          queryKey: ['generatedImages', data.id],
        });
        queryClient.invalidateQueries({
          queryKey: ['generatedVideos', data.id],
        });
      }
    },
    onError: (error: any) => {
      console.error('Load workspace error:', error);
      const errorMessage = extractErrorMessage(
        error,
        'Failed to load workspace'
      );

      toast({
        title: 'Workspace Load Failed',
        description: errorMessage,
        status: 'error',
        duration: 5000,
        isClosable: true,
      });
    },
  });

  // Poll workspace status
  const { data: workspaceData } = useQuery({
    queryKey: ['workspace', workspaceId],
    queryFn: async () => {
      if (!workspaceId) return null;
      const response = await apiClient.GET('/api/video_gen/video_workspace', {
        params: { query: { video_workspace_id: workspaceId } },
      });
      return response.data || null;
    },
    enabled: !!workspaceId,
    refetchInterval: (data) => {
      // Stop polling if completed or failed
      if (
        data &&
        typeof data === 'object' &&
        'status' in data &&
        (data.status === 'completed' || data.status === 'failed')
      ) {
        return false;
      }
      return 15000;
    },
  });

  // Poll generated images - only poll when scene generation is complete
  const { data: imagesData } = useQuery({
    queryKey: ['images', workspaceId],
    queryFn: async () => {
      if (!workspaceId) return [];
      try {
        const response = await apiClient.GET(
          '/api/video_gen/higgsfield/images',
          {
            params: { query: { video_workspace_id: workspaceId } },
          }
        );
        // console.log('Images API response:', response);
        return response.data || [];
      } catch (error) {
        console.error('Images API error:', error);
        // Fallback: return empty array, let the UI show "waiting" state
        return [];
      }
    },
    // Poll images during image generation phases - keep polling until video generation starts
    // Also poll when individual scene images are being regenerated
    enabled: !!workspaceId,
    refetchInterval: (d) => {
      // console.log('refetchInterval', d.state.data);
      const data = d.state.data;
      if (!Array.isArray(data) || data.length === 0) return 5000;

      // console.log('data', data);
      const completed = data.filter(
        (img) => img['status'] === 'completed'
      ).length;
      const failed = data.filter((img) => img['status'] === 'failed').length;
      const processing = data.filter(
        (img) =>
          img['status'] === 'pending' ||
          img['status'] === 'queued' ||
          img['status'] === 'running'
      ).length;

      // console.log('Processing images:', processing);
      // Continue polling if there are any images still processing
      if (processing > 0) {
        return 5000;
      }

      const isImageStageComplete = completed + failed === data.length;

      console.log('Processing isImageStageComplete:', isImageStageComplete);
      // Stop polling images once all are done (completed or failed)
      if (isImageStageComplete) {
        // console.log('All images finished, stopping image polling');
        return false;
      }
      return 5000;
    },
  });

  // Poll custom reference status when we have a created reference ID
  const { data: customReferenceData } = useQuery({
    queryKey: ['customReference', createdReferenceId],
    queryFn: async (): Promise<CustomReference | null> => {
      if (!createdReferenceId) return null;
      try {
        const response = await apiClient.GET(
          '/api/video_gen/higgsfield/custom_reference/{reference_id}',
          {
            params: { path: { reference_id: createdReferenceId } },
          }
        );
        return (response.data || null) as CustomReference | null;
      } catch (error) {
        console.error('Custom reference API error:', error);
        return null;
      }
    },
    enabled: !!createdReferenceId,
    refetchInterval: (data) => {
      // Stop polling once the reference is completed or failed
      if (
        data &&
        typeof data === 'object' &&
        'status' in data &&
        (data.status === 'completed' || data.status === 'failed')
      ) {
        return false;
      }
      // Poll every 15 seconds while processing
      return 15000;
    },
  });

  // Memoize image stats first
  const imageStats = useMemo(() => {
    const images = (imagesData as GeneratedImage[]) || [];
    const completed = images.filter((img) => img.status === 'completed').length;
    const failed = images.filter((img) => img.status === 'failed').length;
    const isComplete =
      images.length > 0 && completed + failed === images.length;
    return {
      total: images.length,
      completed,
      failed,
      isComplete,
    };
  }, [imagesData]);

  // Poll generated videos - only start when images are complete
  const { data: videosData } = useQuery({
    queryKey: ['videos', workspaceId],
    queryFn: async () => {
      if (!workspaceId) return [];
      try {
        // console.log('Polling videos for workspace:', workspaceId);
        const response = await apiClient.GET(
          '/api/video_gen/higgsfield/videos',
          {
            params: { query: { video_workspace_id: workspaceId } },
          }
        );
        // console.log('Videos API response:', response);
        return response.data || [];
      } catch (error) {
        console.error('Videos API error:', error);
        return [];
      }
    },
    // Enable video polling only when images are complete and video generation phase starts
    enabled: (() => {
      const imagesAreComplete =
        imageStats.isComplete && imageStats.completed > 0;
      const isInVideoPhase =
        workspaceData?.status &&
        [
          'soul_images_generated',
          'video_generated',
          'scene_completed',
          'completed',
        ].includes(workspaceData.status);

      const isEnabled =
        !!workspaceId &&
        workspaceData?.status &&
        workspaceData.status !== 'failed' &&
        (imagesAreComplete || isInVideoPhase);
      return isEnabled;
    })(),
    refetchInterval: (data) => {
      if (!Array.isArray(data) || data.length === 0) return 15000;

      const completed = data.filter((vid) => vid.status === 'completed').length;
      const failed = data.filter((vid) => vid.status === 'failed').length;
      const isVideoStageComplete = completed + failed === data.length;

      // Stop polling videos once all are done (completed or failed)
      if (isVideoStageComplete) {
        // console.log('All videos finished, stopping video polling');
        return false;
      }
      return 15000;
    },
  });

  // Memoize video stats after videosData is defined
  const videoStats = useMemo(() => {
    const videos = (videosData as GeneratedVideo[]) || [];
    const completed = videos.filter((vid) => vid.status === 'completed').length;
    const failed = videos.filter((vid) => vid.status === 'failed').length;
    const isComplete =
      videos.length > 0 && completed + failed === videos.length;
    return {
      total: videos.length,
      completed,
      failed,
      isComplete,
    };
  }, [videosData]);

  // Update steps based on workspace status and data availability
  useEffect(() => {
    if (!workspaceData) return;

    const status = workspaceData.status;

    // Initialize scene prompts when scene script becomes available
    if (workspaceData.scene_script && workspaceData.scene_script.length > 0) {
      setScenePrompts((prev) => {
        // Only initialize if we don't have prompts yet or if the length changed
        if (
          prev.length === 0 ||
          prev.length !== workspaceData.scene_script!.length
        ) {
          return workspaceData.scene_script!.map(
            (scene: any) => scene.description || ''
          );
        }
        return prev;
      });
    }

    // Show completion toast only once
    if (
      status === 'completed' &&
      workspaceData.video_url &&
      !shownCompletionToast
    ) {
      setShownCompletionToast(true);
      toast({
        title: 'Video Generation Complete!',
        description:
          'Your video has been successfully generated and is ready to view.',
        status: 'success',
        duration: 5000,
        isClosable: true,
      });
    }

    setSteps((prev) =>
      prev.map((step) => {
        switch (step.id) {
          case 'scene-generation':
            // Show as running if mutation is pending
            if (generateSceneScriptMutation.isPending) {
              // Preserve the step state set by mutation - don't override
              return step;
            }
            // Completed if scene script exists
            if (
              workspaceData.scene_script &&
              workspaceData.scene_script.length > 0
            ) {
              return {
                ...step,
                status: 'completed',
                output: workspaceData.scene_script,
                description:
                  'Video scene is the blueprint of video gen based on lyrics', // Reset to original description
              };
            }
            // Show as pending if workspace exists but no script yet
            return {
              ...step,
              status: 'pending',
              description: workspaceId
                ? 'Ready to generate scene scripts'
                : 'Create workspace first',
            };

          case 'image-generation':
            // Completed if all expected images are done
            if (imageStats.isComplete && imageStats.completed > 0) {
              return { ...step, status: 'completed' };
            }
            // Show as running if images exist but not all are complete
            if (imageStats.total > 0 && !imageStats.isComplete) {
              return { ...step, status: 'running' };
            }
            // Show as pending if scene script exists
            return {
              ...step,
              status: workspaceData.scene_script ? 'pending' : 'pending',
              description: workspaceData.scene_script
                ? 'Ready to generate soul images'
                : 'Generate scene script first',
            };

          case 'video-generation':
            // Completed if all expected videos are done
            if (videoStats.isComplete && videoStats.completed > 0) {
              return { ...step, status: 'completed' };
            }
            // Show as running if videos exist but not all are complete
            if (videoStats.total > 0 && !videoStats.isComplete) {
              return { ...step, status: 'running' };
            }
            // Show as pending if images are completed
            return {
              ...step,
              status: imageStats.completed > 0 ? 'pending' : 'pending',
              description:
                imageStats.completed > 0
                  ? 'Ready to generate videos from images'
                  : 'Generate soul images first',
            };

          case 'video-concatenation':
            // Show as running if mutation is pending
            if (concatenateVideosMutation.isPending) {
              // Preserve the step state set by mutation - don't override
              return step;
            }
            // Completed if final video exists
            if (workspaceData.video_url) {
              return {
                ...step,
                status: 'completed',
                output: workspaceData.video_url,
              };
            }
            // Show as pending if videos are completed
            return {
              ...step,
              status: videoStats.completed > 0 ? 'pending' : 'pending',
              description:
                videoStats.completed > 0
                  ? 'Ready to concatenate videos'
                  : 'Generate videos first',
            };

          default:
            return step;
        }
      })
    );
  }, [
    workspaceData,
    workspaceId,
    imageStats.isComplete,
    imageStats.completed,
    imageStats.total,
    videoStats.isComplete,
    videoStats.completed,
    videoStats.total,
    shownCompletionToast,
    generateSceneScriptMutation.isPending,
    concatenateVideosMutation.isPending,
  ]);

  useEffect(() => {
    const availableImages =
      (imagesData as GeneratedImage[])?.filter(
        (img) => img.raw_image_url || img.min_image_url
      ) || [];
    if (availableImages.length > 0) {
      if (currentImageIndex >= availableImages.length) {
        setCurrentImageIndex(availableImages.length - 1); // Show the latest image
      } else if (currentImageIndex < 0) {
        setCurrentImageIndex(0); // Reset to first image
      }
    }
  }, [imagesData, currentImageIndex]);

  useEffect(() => {
    const availableVideos =
      (videosData as GeneratedVideo[])?.filter((vid) => vid.video_url) || [];
    if (availableVideos.length > 0) {
      if (currentVideoIndex >= availableVideos.length) {
        setCurrentVideoIndex(availableVideos.length - 1); // Show the latest video
      } else if (currentVideoIndex < 0) {
        setCurrentVideoIndex(0); // Reset to first video
      }
    }
  }, [videosData, currentVideoIndex]);

  // Helper functions to determine step availability
  const canExecuteSceneScript = () => {
    return workspaceId && workspaceData?.status === 'workspace_created';
  };

  const canExecuteSoulImages = () => {
    return (
      workspaceId &&
      workspaceData?.status === 'script_generated' &&
      workspaceData?.scene_script
    );
  };

  const canExecuteVideoGeneration = () => {
    return workspaceId && imageStats.total > 0 && imageStats.completed > 0;
  };

  const canExecuteConcatenation = () => {
    return workspaceId && videoStats.total > 0 && videoStats.completed > 0;
  };

  const canRegenerateSceneScript = () => {
    return !!(
      workspaceId &&
      workspaceData?.scene_script &&
      workspaceData.scene_script.length > 0
    );
  };

  const canRegenerateSoulImages = () => {
    return !!(workspaceId && imageStats.total > 0);
  };

  const canRegenerateVideos = () => {
    return !!(workspaceId && videoStats.total > 0);
  };

  const canRegenerateConcatenation = () => {
    return !!(workspaceId && workspaceData?.video_url);
  };

  const isSceneScriptGenerating = () => {
    return generateSceneScriptMutation.isPending;
  };

  useEffect(() => {
    if (workspaceId) {
      setCurrentImageIndex(0);
      setCurrentVideoIndex(0);
      setShownCompletionToast(false);
      setSelectedImageIds(new Set());
      setSelectedVideoIds(new Set());

      setSteps([
        {
          id: 'scene-generation',
          name: 'Scene Script Generation',
          status: 'pending',
          description: 'Generating scene scripts...',
        },
        {
          id: 'image-generation',
          name: 'Image Generation',
          status: 'pending',
          description: 'Generating first frame images for each script...',
        },
        {
          id: 'video-generation',
          name: 'Video Generation',
          status: 'pending',
          description: 'Generating videos from first frames...',
        },
        {
          id: 'video-concatenation',
          name: 'Video Concatenation',
          status: 'pending',
          description: 'Combining all videos into final video...',
        },
      ]);

      // Reset expanded states
      setIsSceneScriptExpanded(false);
    }
  }, [workspaceId]);

  const getStatusColor = (status: VideoGenStep['status']) => {
    switch (status) {
      case 'completed':
        return 'text-grass-500 bg-grass-50 border-grass-200';
      case 'running':
        return 'text-pumpkin-500 bg-pumpkin-50 border-pumpkin-200';
      case 'failed':
        return 'text-strawberry-500 bg-strawberry-50 border-strawberry-200';
      default:
        return 'text-gray-500 bg-gray-50 border-gray-200';
    }
  };

  const getStatusIcon = (status: VideoGenStep['status']) => {
    switch (status) {
      case 'completed':
        return '✓';
      case 'running':
        return '⟳';
      case 'failed':
        return '✗';
      default:
        return '○';
    }
  };

  const renderStepActions = (step: VideoGenStep) => {
    const baseButtonClass =
      'px-4 py-2 rounded text-sm font-medium transition-colors';
    const buttonClass = `${baseButtonClass} bg-accent-primary text-white hover:bg-accent-primary/80 disabled:opacity-50 disabled:cursor-not-allowed`;

    switch (step.id) {
      case 'scene-generation':
        const hasSceneScript = canRegenerateSceneScript();
        const canStartSceneScript = canExecuteSceneScript();
        const isRegenerating = hasSceneScript;
        const isCurrentlyGenerating = isSceneScriptGenerating();
        const canExecute = canStartSceneScript || hasSceneScript;
        return (
          <div className='mt-3'>
            <button
              onClick={() => generateSceneScriptMutation.mutate(isRegenerating)}
              disabled={!canExecute || isCurrentlyGenerating}
              className={buttonClass}
            >
              {isCurrentlyGenerating
                ? isRegenerating
                  ? 'Regenerating...'
                  : 'Generating...'
                : isRegenerating
                  ? 'Regenerate Scene Script'
                  : 'Generate Scene Script'}
            </button>
          </div>
        );

      case 'image-generation':
        const hasSoulImages = canRegenerateSoulImages();
        const isRegeneratingImages = hasSoulImages;
        const canStartImages = canExecuteSoulImages();
        // Check if images are currently being generated (background processing)
        const imagesCurrentlyGenerating =
          imageStats.total > 0 && !imageStats.isComplete;

        // Don't allow regeneration while images are actively being generated
        const allowImageRegeneration =
          hasSoulImages &&
          !generateSoulImagesMutation.isPending &&
          !imagesCurrentlyGenerating;
        // Don't allow starting images if scene script is still generating
        const sceneScriptComplete =
          !isSceneScriptGenerating() && canRegenerateSceneScript();
        const canProceedWithImages =
          sceneScriptComplete &&
          (canStartImages || allowImageRegeneration) &&
          !imagesCurrentlyGenerating;

        // Determine the actual action: regenerate only if images exist AND we can't start new ones
        const isActualRegeneration = hasSoulImages && !canStartImages;

        return (
          <div className='mt-3'>
            <button
              onClick={() =>
                generateSoulImagesMutation.mutate(isRegeneratingImages)
              }
              disabled={
                !canProceedWithImages || generateSoulImagesMutation.isPending
              }
              className={buttonClass}
            >
              {generateSoulImagesMutation.isPending
                ? isActualRegeneration
                  ? 'Regenerating...'
                  : 'Generating...'
                : isActualRegeneration
                  ? 'Regenerate Soul Images'
                  : 'Generate Soul Images'}
            </button>
          </div>
        );

      case 'video-generation':
        const hasVideos = canRegenerateVideos();
        const isRegeneratingVideos = hasVideos;
        const canStartVideos = canExecuteVideoGeneration();
        // Check if videos are currently being generated (background processing)
        const videosCurrentlyGenerating =
          videoStats.total > 0 && !videoStats.isComplete;

        // Don't allow regeneration while videos are actively being generated
        const allowVideoRegeneration =
          hasVideos &&
          !generateVideosMutation.isPending &&
          !videosCurrentlyGenerating;
        // Don't allow starting videos if images are still generating
        const imagesComplete =
          !generateSoulImagesMutation.isPending &&
          imageStats.isComplete &&
          imageStats.completed > 0;
        const canProceedWithVideos =
          imagesComplete &&
          (canStartVideos || allowVideoRegeneration) &&
          !videosCurrentlyGenerating;

        // Determine the actual action: regenerate only if videos exist AND we can't start new ones
        const isActualVideoRegeneration = hasVideos && !canStartVideos;

        return (
          <div className='mt-3'>
            <button
              onClick={() => {
                const images = (imagesData as GeneratedImage[]) || [];
                const completedImages = images.filter(
                  (img) =>
                    img.status === 'completed' &&
                    (img.raw_image_url || img.min_image_url)
                );

                // Use selected images if any are selected, otherwise use all completed images
                const imagesToUse =
                  selectedImageIds.size > 0
                    ? completedImages.filter((img) =>
                        selectedImageIds.has(img.id)
                      )
                    : completedImages;

                const imageIds = imagesToUse.map((image) => image.id);

                generateVideosMutation.mutate({
                  imageIds,
                  regenerate: isRegeneratingVideos,
                });
              }}
              disabled={
                !canProceedWithVideos || generateVideosMutation.isPending
              }
              className={buttonClass}
            >
              {(() => {
                const images = (imagesData as GeneratedImage[]) || [];
                const completedImages = images.filter(
                  (img) =>
                    img.status === 'completed' &&
                    (img.raw_image_url || img.min_image_url)
                );
                const imagesToUse =
                  selectedImageIds.size > 0
                    ? completedImages.filter((img) =>
                        selectedImageIds.has(img.id)
                      )
                    : completedImages;
                const imageCount = imagesToUse.length;

                if (generateVideosMutation.isPending) {
                  return isActualVideoRegeneration
                    ? 'Regenerating...'
                    : 'Generating...';
                }

                const baseText = isActualVideoRegeneration
                  ? 'Regenerate Videos'
                  : 'Generate Videos';
                return imageCount > 0
                  ? `${baseText} (${imageCount} images)`
                  : baseText;
              })()}
            </button>
          </div>
        );

      case 'video-concatenation':
        const hasConcat = canRegenerateConcatenation();
        const isRegeneratingConcat = hasConcat;
        const canStartConcat = canExecuteConcatenation();
        // Check if concatenation is currently happening (background processing)
        const concatCurrentlyGenerating =
          concatenateVideosMutation.isPending ||
          (workspaceData?.status &&
            ['video_generated', 'scene_completed'].includes(
              workspaceData.status
            ));

        // Don't allow regeneration while concatenation is actively happening
        const allowConcatRegeneration =
          hasConcat &&
          !concatenateVideosMutation.isPending &&
          !concatCurrentlyGenerating;
        // Don't allow starting concatenation if videos are still generating
        const videosComplete =
          !generateVideosMutation.isPending &&
          videoStats.isComplete &&
          videoStats.completed > 0;
        const canProceedWithConcat =
          videosComplete && (canStartConcat || allowConcatRegeneration);

        // Determine the actual action: regenerate only if concat exists AND we can't start new ones
        const isActualConcatRegeneration = hasConcat && !canProceedWithConcat;

        return (
          <div className='mt-3'>
            <div>
              {concatenateVideosMutation.isPending ? 'true' : 'false'},{' '}
              {!!canProceedWithConcat ? 'true' : 'false'},{' '}
              {!!videosComplete ? 'true' : 'false'}
              {!!(canStartConcat || allowConcatRegeneration) ? 'true' : 'false'}
              {!!concatCurrentlyGenerating ? 'true' : 'false'}
            </div>
            <button
              onClick={() => {
                const videos = (videosData as GeneratedVideo[]) || [];
                const completedVideos = videos.filter(
                  (vid) => vid.status === 'completed' && vid.video_url
                );

                // Use selected videos if any are selected, otherwise use all completed videos
                const videosToUse =
                  selectedVideoIds.size > 0
                    ? completedVideos.filter((vid) =>
                        selectedVideoIds.has(vid.id)
                      )
                    : completedVideos;

                const videoIds = videosToUse.map((video) => video.id);

                concatenateVideosMutation.mutate({
                  videoIds,
                  regenerate: isRegeneratingConcat,
                });
              }}
              disabled={
                !canProceedWithConcat || concatenateVideosMutation.isPending
              }
              className={buttonClass}
            >
              {(() => {
                const videos = (videosData as GeneratedVideo[]) || [];
                const completedVideos = videos.filter(
                  (vid) => vid.status === 'completed' && vid.video_url
                );
                const videosToUse =
                  selectedVideoIds.size > 0
                    ? completedVideos.filter((vid) =>
                        selectedVideoIds.has(vid.id)
                      )
                    : completedVideos;
                const videoCount = videosToUse.length;

                if (concatenateVideosMutation.isPending) {
                  return isActualConcatRegeneration
                    ? 'Regenerating...'
                    : 'Concatenating...';
                }

                const baseText = isActualConcatRegeneration
                  ? 'Regenerate Final Video'
                  : 'Concatenate Videos';
                return videoCount > 0
                  ? `${baseText} (${videoCount} videos)`
                  : baseText;
              })()}
            </button>
          </div>
        );

      default:
        return null;
    }
  };

  const renderStepOutput = (step: VideoGenStep) => {
    if (
      !step.output &&
      step.id !== 'image-generation' &&
      step.id !== 'video-generation'
    )
      return null;

    switch (step.id) {
      case 'scene-generation':
        return (
          <div className='mt-4 space-y-2'>
            <div className='flex items-center justify-between'>
              <h4 className='text-sm font-medium text-foreground-primary'>
                Generated Scenes ({step.output?.length || 0}):
              </h4>
              {step.output?.length > 0 && (
                <button
                  onClick={() =>
                    setIsSceneScriptExpanded(!isSceneScriptExpanded)
                  }
                  className='flex items-center gap-1 text-xs text-foreground-secondary hover:text-foreground-primary'
                >
                  {isSceneScriptExpanded ? 'Collapse' : 'Expand All'}
                  <span
                    className='transform transition-transform duration-200'
                    style={{
                      transform: isSceneScriptExpanded
                        ? 'rotate(180deg)'
                        : 'rotate(0deg)',
                    }}
                  >
                    ▼
                  </span>
                </button>
              )}
            </div>

            {step.output
              ?.slice(0, isSceneScriptExpanded ? step.output.length : 3)
              .map((scene: any, idx: number) => (
                <div
                  key={idx}
                  className='rounded border border-border-secondary bg-background-primary p-3'
                >
                  <div className='mb-1 text-xs text-foreground-secondary'>
                    Scene {idx + 1}: {scene.start_s?.toFixed(1)}s -{' '}
                    {scene.end_s?.toFixed(1)}s
                  </div>
                  <div className='mb-2 text-sm text-foreground-primary'>
                    {scene.description}
                  </div>
                  {scene.roll_type && (
                    <div className='mb-2 text-xs text-foreground-secondary'>
                      Type: {scene.roll_type}
                    </div>
                  )}

                  {/* Editable prompt for image generation */}
                  <div className='mt-3 border-t border-border-secondary pt-3'>
                    <label className='mb-1 block text-xs font-medium text-foreground-secondary'>
                      Image Generation Prompt:
                    </label>
                    <textarea
                      value={scenePrompts[idx] || scene.description || ''}
                      onChange={(e) => {
                        const newPrompts = [...scenePrompts];
                        newPrompts[idx] = e.target.value;
                        setScenePrompts(newPrompts);
                      }}
                      className='w-full resize-y rounded border border-border-secondary bg-background-secondary p-2 text-xs text-foreground-primary'
                      rows={3}
                      placeholder='Enter prompt for image generation...'
                    />
                  </div>
                </div>
              ))}

            {step.output?.length > 3 && !isSceneScriptExpanded && (
              <button
                onClick={() => setIsSceneScriptExpanded(true)}
                className='w-full rounded border border-border-secondary bg-background-secondary py-2 text-center text-xs text-foreground-secondary hover:text-foreground-primary'
              >
                Show {step.output.length - 3} more scenes...
              </button>
            )}
          </div>
        );

      case 'image-generation':
        const images = (imagesData as GeneratedImage[]) || [];
        const completedImages = images.filter(
          (img) => img.status === 'completed'
        );
        const hasImages = images.length > 0;
        const availableImages = images.filter(
          (img) => img.raw_image_url || img.min_image_url
        );

        // Create a lookup map for faster thumbnail navigation
        const imageIdToAvailableIndex = new Map<string, number>();
        availableImages.forEach((img, index) => {
          imageIdToAvailableIndex.set(img.id, index);
        });

        // console.log('Rendering images:', {
        //   images,
        //   completedImages,
        //   hasImages,
        //   availableImages,
        //   imagesData,
        //   workspaceStatus: workspaceData?.status,
        //   imagePollingEnabled:
        //     !!workspaceId &&
        //     workspaceData?.status &&
        //     ['script_generated', 'soul_images_generated'].includes(
        //       workspaceData.status
        //     ),
        // });

        return (
          <div className='mt-4'>
            <h4 className='mb-3 text-sm font-medium text-foreground-primary'>
              Generated Images ({completedImages.length}/{images.length})
            </h4>

            {!hasImages ? (
              <div className='rounded border border-border-secondary bg-background-secondary p-4 text-center text-foreground-secondary'>
                Waiting for images to be generated...
              </div>
            ) : (
              <div className='space-y-4'>
                {/* Debug: Show all image statuses */}
                <div className='text-xs text-gray-500'>
                  Images:{' '}
                  {images
                    .map(
                      (img) =>
                        `${img.status}${img.raw_image_url ? '(has_url)' : '(no_url)'}`
                    )
                    .join(', ')}
                </div>
                <div className='text-xs text-gray-500'>
                  Available Images: {availableImages.length}, Current Index:{' '}
                  {currentImageIndex}
                </div>

                {/* Main Carousel - Show whenever there are images with URLs */}
                {availableImages.length > 0 ? (
                  <div className='relative'>
                    <div className='mx-auto aspect-video max-w-lg overflow-hidden rounded-lg border bg-gray-100'>
                      <ImageWithFallback
                        src={
                          availableImages[currentImageIndex]?.raw_image_url ||
                          availableImages[currentImageIndex]?.min_image_url
                        }
                        alt={`Scene ${(availableImages[currentImageIndex]?.scene_index ?? currentImageIndex) + 1}`}
                        className='h-full w-full object-contain'
                        // onLoad={() =>
                        //   console.log(
                        //     'Carousel image loaded:',
                        //     availableImages[currentImageIndex]?.raw_image_url ||
                        //       availableImages[currentImageIndex]?.min_image_url
                        //   )
                        // }
                        onError={(e) => {
                          console.error(
                            'Carousel image failed to load:',
                            availableImages[currentImageIndex]?.raw_image_url ||
                              availableImages[currentImageIndex]?.min_image_url,
                            e
                          );
                        }}
                      />
                      <div className='bg-opacity-70 absolute top-2 left-2 rounded bg-black px-2 py-1 text-sm text-white'>
                        Scene{' '}
                        {(availableImages[currentImageIndex]?.scene_index ??
                          currentImageIndex) + 1}
                      </div>
                      <div className='bg-opacity-70 absolute top-2 right-2 rounded bg-black px-2 py-1 text-sm text-white'>
                        {currentImageIndex + 1} / {availableImages.length}
                      </div>
                      <div className='bg-opacity-70 absolute bottom-2 left-2 rounded bg-black px-2 py-1 text-sm text-white'>
                        <button
                          onClick={() => {
                            const sceneIndex =
                              availableImages[currentImageIndex]?.scene_index ??
                              currentImageIndex;
                            regenerateSceneImageMutation.mutate({ sceneIndex });
                          }}
                          disabled={regenerateSceneImageMutation.isPending}
                          className='hover:bg-opacity-90 disabled:opacity-50'
                        >
                          {regenerateSceneImageMutation.isPending
                            ? 'Regenerating...'
                            : `Regenerate Scene ${(availableImages[currentImageIndex]?.scene_index ?? currentImageIndex) + 1} Image`}
                        </button>
                      </div>
                    </div>

                    {/* Carousel Controls */}
                    {availableImages.length > 1 && (
                      <>
                        <button
                          onClick={() =>
                            setCurrentImageIndex((prev) =>
                              prev > 0 ? prev - 1 : availableImages.length - 1
                            )
                          }
                          className='bg-opacity-70 hover:bg-opacity-90 absolute top-1/2 left-2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full bg-black text-white'
                        >
                          ←
                        </button>
                        <button
                          onClick={() =>
                            setCurrentImageIndex((prev) =>
                              prev < availableImages.length - 1 ? prev + 1 : 0
                            )
                          }
                          className='bg-opacity-70 hover:bg-opacity-90 absolute top-1/2 right-2 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full bg-black text-white'
                        >
                          →
                        </button>
                      </>
                    )}

                    {/* Current image prompt - editable */}
                    {availableImages[currentImageIndex] && (
                      <div className='mx-auto mt-4 max-w-lg'>
                        <label className='mb-2 block text-sm font-medium text-foreground-primary'>
                          Edit Prompt for Scene{' '}
                          {(availableImages[currentImageIndex]?.scene_index ??
                            currentImageIndex) + 1}
                          :
                        </label>
                        <textarea
                          value={
                            scenePrompts[
                              availableImages[currentImageIndex]?.scene_index ??
                                currentImageIndex
                            ] ||
                            availableImages[currentImageIndex].prompt ||
                            ''
                          }
                          onChange={(e) => {
                            const sceneIndex =
                              availableImages[currentImageIndex]?.scene_index ??
                              currentImageIndex;
                            const newPrompts = [...scenePrompts];
                            newPrompts[sceneIndex] = e.target.value;
                            setScenePrompts(newPrompts);
                          }}
                          className='w-full resize-y rounded border border-border-secondary bg-background-primary p-3 text-sm text-foreground-primary'
                          rows={3}
                          placeholder='Enter prompt for this scene...'
                        />
                      </div>
                    )}
                  </div>
                ) : (
                  <div className='rounded border border-border-secondary bg-background-secondary p-4 text-center text-foreground-secondary'>
                    Images are generating but URLs not yet available...
                  </div>
                )}

                {/* Image Selection Controls */}
                <div className='mb-4 flex items-center gap-4'>
                  <div className='text-sm text-foreground-secondary'>
                    {selectedImageIds.size > 0
                      ? `${selectedImageIds.size} images selected for video generation`
                      : 'No images selected - will use all completed images'}
                  </div>
                  <div className='flex gap-2'>
                    <button
                      onClick={() => {
                        const completedImageIds = images
                          .filter(
                            (img) =>
                              img.status === 'completed' &&
                              (img.raw_image_url || img.min_image_url)
                          )
                          .map((img) => img.id);
                        setSelectedImageIds(new Set(completedImageIds));
                      }}
                      className='text-accent-primary hover:text-accent-primary/80 text-sm'
                    >
                      Select All
                    </button>
                    <button
                      onClick={() => setSelectedImageIds(new Set())}
                      className='text-accent-primary hover:text-accent-primary/80 text-sm'
                    >
                      Clear Selection
                    </button>
                  </div>
                </div>

                {/* Thumbnail Grid */}
                <div className='grid grid-cols-6 gap-2'>
                  {images.map((image: GeneratedImage, idx: number) => (
                    <div
                      key={image.id}
                      className={`relative cursor-pointer rounded border-2 ${
                        availableImages[currentImageIndex]?.id === image.id
                          ? 'border-grass-500'
                          : 'border-transparent hover:border-gray-300'
                      }`}
                      onClick={() => {
                        // For completed images, toggle selection
                        if (
                          image.status === 'completed' &&
                          (image.raw_image_url || image.min_image_url)
                        ) {
                          setSelectedImageIds((prev) => {
                            const newSet = new Set(prev);
                            if (newSet.has(image.id)) {
                              newSet.delete(image.id);
                            } else {
                              newSet.add(image.id);
                            }
                            return newSet;
                          });
                        }

                        // Also update the carousel view
                        const index = imageIdToAvailableIndex.get(image.id);
                        if (index !== undefined) setCurrentImageIndex(index);
                      }}
                    >
                      <div className='aspect-square overflow-hidden rounded bg-gray-100'>
                        {image.raw_image_url || image.min_image_url ? (
                          <ImageWithFallback
                            src={image.min_image_url || image.raw_image_url}
                            alt={`Scene ${(image.scene_index !== undefined ? image.scene_index : idx) + 1}`}
                            className='h-full w-full object-cover'
                          />
                        ) : (
                          <div className='flex h-full w-full items-center justify-center'>
                            <div className='h-3 w-3 animate-spin rounded-full border border-pumpkin-500 border-t-transparent'></div>
                          </div>
                        )}
                        <div className='bg-opacity-70 absolute top-1 left-1 rounded bg-black px-1 text-xs text-white'>
                          {(image.scene_index !== undefined
                            ? image.scene_index
                            : idx) + 1}
                        </div>
                        {/* Selection indicator for completed images */}
                        {selectedImageIds.has(image.id) && (
                          <div className='absolute right-1 bottom-1'>
                            <span className='bg-opacity-90 rounded-full bg-white px-1 text-2xl font-black text-green-600 shadow-lg'>
                              ✓
                            </span>
                          </div>
                        )}
                      </div>
                    </div>
                  ))}
                </div>

                <div className='text-center text-xs text-foreground-secondary'>
                  Status: {completedImages.length} completed,{' '}
                  {images.filter((img) => img.status === 'failed').length}{' '}
                  failed,{' '}
                  {
                    images.filter(
                      (img) =>
                        img.status === 'queued' || img.status === 'pending'
                    ).length
                  }{' '}
                  pending
                </div>
              </div>
            )}
          </div>
        );

      case 'video-generation':
        const videos = (videosData as GeneratedVideo[]) || [];
        const completedVideos = videos.filter(
          (vid) => vid.status === 'completed'
        );
        const hasVideos = videos.length > 0;
        const availableVideos = videos.filter((vid) => vid.video_url);

        // Create a lookup map for faster video thumbnail navigation
        const videoIdToAvailableIndex = new Map<string, number>();
        availableVideos.forEach((vid, index) => {
          videoIdToAvailableIndex.set(vid.id, index);
        });

        return (
          <div className='mt-4'>
            <h4 className='mb-3 text-sm font-medium text-foreground-primary'>
              Generated Videos ({completedVideos.length}/{videos.length})
            </h4>

            {!hasVideos ? (
              <div className='rounded border border-border-secondary bg-background-secondary p-4 text-center text-foreground-secondary'>
                Waiting for videos to be generated from images...
              </div>
            ) : (
              <div className='space-y-4'>
                {/* Debug: Show all video statuses */}
                <div className='text-xs text-gray-500'>
                  Videos:{' '}
                  {videos
                    .map(
                      (vid) =>
                        `${vid.status}${vid.video_url ? '(has_url)' : '(no_url)'}`
                    )
                    .join(', ')}
                </div>
                <div className='text-xs text-gray-500'>
                  Available Videos: {availableVideos.length}, Current Index:{' '}
                  {currentVideoIndex}
                </div>

                {/* Main Video Carousel - Show whenever there are videos with URLs */}
                {availableVideos.length > 0 ? (
                  <div className='relative'>
                    <div className='mx-auto aspect-video max-w-lg overflow-hidden rounded-lg border bg-gray-100'>
                      <video
                        src={availableVideos[currentVideoIndex]?.video_url}
                        className='h-full w-full object-contain'
                        controls
                        muted
                        playsInline
                        // onLoadStart={() =>
                        //   console.log(
                        //     'Video loaded:',
                        //     availableVideos[currentVideoIndex]?.video_url
                        //   )
                        // }
                        onError={(e) => {
                          console.error(
                            'Video failed to load:',
                            availableVideos[currentVideoIndex]?.video_url,
                            e
                          );
                        }}
                      />
                      <div className='bg-opacity-70 absolute bottom-2 left-2 rounded bg-black px-2 py-1 text-sm text-white'>
                        Scene{' '}
                        {(availableVideos[currentVideoIndex]?.scene_index ??
                          currentVideoIndex) + 1}
                      </div>
                      <div className='bg-opacity-70 absolute right-2 bottom-2 rounded bg-black px-2 py-1 text-sm text-white'>
                        {currentVideoIndex + 1} / {availableVideos.length}
                      </div>
                    </div>

                    {/* Navigation buttons */}
                    {availableVideos.length > 1 && (
                      <>
                        <button
                          onClick={() =>
                            setCurrentVideoIndex((prev) =>
                              prev > 0 ? prev - 1 : availableVideos.length - 1
                            )
                          }
                          className='bg-opacity-50 hover:bg-opacity-70 absolute top-1/2 left-2 -translate-y-1/2 rounded-full bg-black p-2 text-white'
                        >
                          ←
                        </button>
                        <button
                          onClick={() =>
                            setCurrentVideoIndex((prev) =>
                              prev < availableVideos.length - 1 ? prev + 1 : 0
                            )
                          }
                          className='bg-opacity-50 hover:bg-opacity-70 absolute top-1/2 right-2 -translate-y-1/2 rounded-full bg-black p-2 text-white'
                        >
                          →
                        </button>
                      </>
                    )}
                  </div>
                ) : (
                  <div className='rounded border border-border-secondary bg-background-secondary p-4 text-center text-foreground-secondary'>
                    Videos are generating but URLs not yet available...
                  </div>
                )}

                {/* Video Selection Controls */}
                <div className='mb-4 flex items-center gap-4'>
                  <div className='text-sm text-foreground-secondary'>
                    {selectedVideoIds.size > 0
                      ? `${selectedVideoIds.size} videos selected for concatenation`
                      : 'No videos selected - will use all completed videos'}
                  </div>
                  <div className='flex gap-2'>
                    <button
                      onClick={() => {
                        const completedVideoIds = videos
                          .filter(
                            (vid) => vid.status === 'completed' && vid.video_url
                          )
                          .map((vid) => vid.id);
                        setSelectedVideoIds(new Set(completedVideoIds));
                      }}
                      className='text-accent-primary hover:text-accent-primary/80 text-sm'
                    >
                      Select All
                    </button>
                    <button
                      onClick={() => setSelectedVideoIds(new Set())}
                      className='text-accent-primary hover:text-accent-primary/80 text-sm'
                    >
                      Clear Selection
                    </button>
                  </div>
                </div>

                {/* Thumbnail Grid */}
                <div className='grid grid-cols-6 gap-2'>
                  {videos.map((video: GeneratedVideo, idx: number) => (
                    <div
                      key={video.id}
                      className={`relative cursor-pointer rounded border-2 transition-all ${
                        availableVideos.length > 0 &&
                        availableVideos[currentVideoIndex]?.id === video.id
                          ? 'border-pumpkin-400 ring-2 ring-pumpkin-200'
                          : 'border-transparent hover:border-gray-300'
                      }`}
                      onClick={() => {
                        // For completed videos, toggle selection
                        if (video.status === 'completed' && video.video_url) {
                          setSelectedVideoIds((prev) => {
                            const newSet = new Set(prev);
                            if (newSet.has(video.id)) {
                              newSet.delete(video.id);
                            } else {
                              newSet.add(video.id);
                            }
                            return newSet;
                          });
                        }

                        // Also update the carousel view
                        const index = videoIdToAvailableIndex.get(video.id);
                        if (index !== undefined) setCurrentVideoIndex(index);
                      }}
                    >
                      <div className='aspect-square overflow-hidden rounded bg-gray-100'>
                        {video.video_url ? (
                          <video
                            src={video.video_url}
                            className='h-full w-full object-cover'
                            muted
                            playsInline
                          />
                        ) : (
                          <div className='flex h-full w-full items-center justify-center'>
                            {video.status === 'failed' ? (
                              <div className='text-xs text-strawberry-500'>
                                ✗
                              </div>
                            ) : (
                              <div className='h-3 w-3 animate-spin rounded-full border border-pumpkin-500 border-t-transparent'></div>
                            )}
                          </div>
                        )}
                        <div className='bg-opacity-70 absolute top-1 left-1 rounded bg-black px-1 text-xs text-white'>
                          {(video.scene_index !== undefined
                            ? video.scene_index
                            : idx) + 1}
                        </div>
                        <div className='bg-opacity-70 absolute right-1 bottom-1 rounded bg-black px-1 text-xs text-white'>
                          {video.status === 'completed'
                            ? '✓'
                            : video.status === 'failed'
                              ? '✗'
                              : ''}
                        </div>
                        {/* Selection indicator for completed videos */}
                        {selectedVideoIds.has(video.id) && (
                          <div className='absolute top-1 right-1'>
                            <span className='bg-opacity-90 rounded-full bg-white px-1 text-2xl font-black text-green-600 shadow-lg'>
                              ✓
                            </span>
                          </div>
                        )}
                      </div>
                    </div>
                  ))}
                </div>

                <div className='text-center text-xs text-foreground-secondary'>
                  Status: {completedVideos.length} completed,{' '}
                  {videos.filter((vid) => vid.status === 'failed').length}{' '}
                  failed,{' '}
                  {
                    videos.filter(
                      (vid) =>
                        vid.status === 'queued' || vid.status === 'pending'
                    ).length
                  }{' '}
                  pending
                </div>
              </div>
            )}
          </div>
        );

      default:
        return null;
    }
  };

  return (
    <div className='h-full w-full overflow-y-auto p-6'>
      <h1 className='mb-2 text-2xl font-bold text-foreground-primary'>
        Video Generation Prototype
      </h1>
      <div className='mb-3 flex items-center gap-4'>
        {workspaceId && (
          <div className='text-sm text-foreground-secondary'>
            Workspace: <span className='font-mono'>{workspaceId}</span>
          </div>
        )}
        {clipId && workspaceId && (
          <div className='text-sm text-foreground-secondary'>
            Clip: <span className='font-mono'>{clipId}</span>
          </div>
        )}
        {workspaceData?.status && (
          <div className='text-sm text-foreground-secondary'>
            Status:{' '}
            <span className='rounded bg-gray-100 px-1 font-mono'>
              {workspaceData.status}
            </span>
          </div>
        )}
      </div>

      <div className='mb-8 rounded-lg border border-border-primary bg-background-secondary p-4'>
        <div className='mb-4 flex border-b border-border-secondary'>
          <button
            onClick={() => setActiveTab('generate')}
            className={`rounded-t-lg border-b-2 px-4 py-2 text-sm font-medium transition-colors ${
              activeTab === 'generate'
                ? 'border-accent-primary text-accent-primary bg-background-primary'
                : 'border-transparent text-foreground-secondary hover:text-foreground-primary'
            }`}
          >
            Generate Video
          </button>
          <button
            onClick={() => setActiveTab('reference')}
            className={`rounded-t-lg border-b-2 px-4 py-2 text-sm font-medium transition-colors ${
              activeTab === 'reference'
                ? 'border-accent-primary text-accent-primary bg-background-primary'
                : 'border-transparent text-foreground-secondary hover:text-foreground-primary'
            }`}
          >
            Custom Reference
          </button>
          <button
            onClick={() => setActiveTab('load')}
            className={`rounded-t-lg border-b-2 px-4 py-2 text-sm font-medium transition-colors ${
              activeTab === 'load'
                ? 'border-accent-primary text-accent-primary bg-background-primary'
                : 'border-transparent text-foreground-secondary hover:text-foreground-primary'
            }`}
          >
            Load Workspace
          </button>
        </div>

        {/* Generate Video Tab */}
        {activeTab === 'generate' && (
          <div className='space-y-4'>
            <div>
              <label className='mb-2 block text-sm font-medium'>
                Clip ID *
              </label>
              <input
                type='text'
                placeholder='Enter clip ID'
                value={clipId}
                onChange={(e) => setClipId(e.target.value)}
                className='w-full rounded border border-border-secondary p-3'
              />
            </div>

            <div>
              <label className='mb-2 block text-sm font-medium'>
                Custom Prompt (Optional)
              </label>
              <input
                type='text'
                placeholder='Describe the video style or theme'
                value={prompt}
                onChange={(e) => setPrompt(e.target.value)}
                className='w-full rounded border border-border-secondary p-3'
              />
            </div>

            <div>
              <label className='mb-2 block text-sm font-medium'>
                Reference Image URL (Optional)
              </label>
              <input
                type='text'
                placeholder='Enter image URL for character/style reference'
                value={imageUrl}
                onChange={(e) => setImageUrl(e.target.value)}
                className='w-full rounded border border-border-secondary p-3'
              />
              <p className='mt-1 text-xs text-gray-500'>
                Use an image URL as reference for character or style consistency
              </p>
            </div>

            <div>
              <label className='mb-2 block text-sm font-medium'>
                Custom Reference ID (Optional)
              </label>
              <input
                type='text'
                placeholder='Enter custom reference ID for character consistency'
                value={customReferenceId}
                onChange={(e) => setCustomReferenceId(e.target.value)}
                className='w-full rounded border border-border-secondary p-3'
              />
              <div className='mt-1 flex items-center justify-between'>
                <p className='text-xs text-gray-500'>
                  Use a custom reference ID to maintain character consistency
                  across scenes
                </p>
                {createdReferenceId && (
                  <button
                    onClick={() => setCustomReferenceId(createdReferenceId)}
                    className='text-accent-primary hover:text-accent-primary/80 text-xs'
                  >
                    Use Created Reference
                  </button>
                )}
              </div>
            </div>
            <button
              onClick={() => createWorkspaceMutation.mutate()}
              disabled={
                createWorkspaceMutation.isPending || !clipId || !!workspaceId
              }
              className='bg-accent-primary hover:bg-accent-primary/80 rounded px-6 py-3 text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50'
            >
              {createWorkspaceMutation.isPending
                ? 'Creating Workspace...'
                : workspaceId
                  ? 'Workspace Created'
                  : 'Create Workspace'}
            </button>

            {workspaceId && (
              <div className='mt-2 flex items-center justify-between'>
                <div className='text-sm text-grass-600'>
                  ✓ Workspace created. Use the step buttons below to proceed
                  through each stage.
                </div>
                <button
                  onClick={() => {
                    setWorkspaceId('');
                    setShownCompletionToast(false);
                    setCurrentImageIndex(0);
                    setCurrentVideoIndex(0);
                    setSelectedImageIds(new Set());
                    setSelectedVideoIds(new Set());
                    setScenePrompts([]);
                  }}
                  className='text-sm text-red-600 underline hover:text-red-800'
                >
                  Reset Workspace
                </button>
              </div>
            )}

            {createWorkspaceMutation.error && (
              <div className='mt-4 rounded-lg border border-red-200 bg-red-50 p-4'>
                <h4 className='text-sm font-medium text-red-800'>
                  Workspace Creation Failed
                </h4>
                <p className='mt-1 text-sm text-red-700'>
                  {(createWorkspaceMutation.error as any)?.response?.data
                    ?.detail ||
                    (createWorkspaceMutation.error as any)?.response?.data
                      ?.message ||
                    createWorkspaceMutation.error.message ||
                    'An error occurred during workspace creation.'}
                </p>
              </div>
            )}
          </div>
        )}

        {activeTab === 'reference' && (
          <div className='space-y-4'>
            <div>
              <label className='mb-2 block text-sm font-medium'>
                Reference Name *
              </label>
              <input
                type='text'
                placeholder='Enter a name for this reference'
                value={referenceName}
                onChange={(e) => setReferenceName(e.target.value)}
                className='w-full rounded border border-border-secondary p-3'
              />
            </div>

            <div>
              <label className='mb-2 block text-sm font-medium'>
                Reference Images *
              </label>
              {referenceImages.map((image, index) => (
                <div key={index} className='mb-2 flex gap-2'>
                  <input
                    type='text'
                    placeholder={`Image URL ${index + 1}`}
                    value={image}
                    onChange={(e) => {
                      const newImages = [...referenceImages];
                      newImages[index] = e.target.value;
                      setReferenceImages(newImages);
                    }}
                    className='flex-1 rounded border border-border-secondary p-3'
                  />
                  {referenceImages.length > 1 && (
                    <button
                      onClick={() => {
                        const newImages = referenceImages.filter(
                          (_, i) => i !== index
                        );
                        setReferenceImages(newImages);
                      }}
                      className='px-3 py-2 text-red-500 hover:text-red-700'
                    >
                      ✕
                    </button>
                  )}
                </div>
              ))}
              <button
                onClick={() => setReferenceImages([...referenceImages, ''])}
                className='text-accent-primary hover:text-accent-primary/80 text-sm'
              >
                + Add Another Image
              </button>
              <p className='mt-1 text-xs text-gray-500'>
                Upload 3-5 images of the same character/object for best results
              </p>
            </div>

            <button
              onClick={() => createCustomReferenceMutation.mutate()}
              disabled={
                createCustomReferenceMutation.isPending ||
                !referenceName.trim() ||
                referenceImages.filter((img) => img.trim()).length === 0
              }
              className='bg-accent-primary hover:bg-accent-primary/80 rounded px-6 py-3 text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50'
            >
              {createCustomReferenceMutation.isPending
                ? 'Creating Reference...'
                : 'Create Custom Reference'}
            </button>

            {createdReferenceId && (
              <div className='bg-grass-50 rounded-lg border border-grass-200 p-4'>
                <h4 className='mb-2 text-sm font-medium text-grass-800'>
                  Reference Created
                </h4>
                <div className='flex items-center gap-2'>
                  <code className='rounded border px-2 py-1 text-xs text-white'>
                    {createdReferenceId}
                  </code>
                  <button
                    onClick={() => {
                      navigator.clipboard.writeText(createdReferenceId);
                    }}
                    className='cursor-pointer text-xs text-grass-600 hover:text-grass-800'
                  >
                    Copy ID
                  </button>
                </div>
                {customReferenceData && (
                  <div className='mt-2 flex items-center gap-2'>
                    <span className='text-xs font-medium text-grass-700'>
                      Status:
                    </span>
                    <span
                      className={`rounded px-2 py-1 text-xs font-medium ${
                        customReferenceData.status === 'completed'
                          ? 'bg-green-300 text-green-800'
                          : customReferenceData.status === 'failed'
                            ? 'bg-red-300 text-red-800'
                            : customReferenceData.status === 'in_progress'
                              ? 'bg-blue-300 text-blue-800'
                              : customReferenceData.status === 'queued'
                                ? 'bg-yellow-300 text-yellow-800'
                                : 'bg-gray-100 text-gray-800'
                      }`}
                    >
                      {customReferenceData.status}
                    </span>
                  </div>
                )}
                <p className='mt-1 text-xs text-grass-600'>
                  {customReferenceData?.status === 'completed'
                    ? 'Reference is ready to use for video generation!'
                    : customReferenceData?.status === 'failed'
                      ? 'Reference failed to process. You may need to create a new one.'
                      : 'Reference is being processed. Video generation will be enabled when ready.'}
                </p>
                <p className='mt-1 text-xs text-grass-600'>
                  (This ID has also been auto-filled in the Generate Video tab)
                </p>
              </div>
            )}

            {createCustomReferenceMutation.error && (
              <div className='rounded-lg border border-red-200 bg-red-50 p-4'>
                <p className='text-sm text-red-800'>
                  Error: {createCustomReferenceMutation.error.message}
                </p>
              </div>
            )}
          </div>
        )}

        {/* Load Workspace Tab */}
        {activeTab === 'load' && (
          <div className='space-y-4'>
            <div>
              <label className='mb-2 block text-sm font-medium'>
                Workspace ID *
              </label>
              <input
                type='text'
                placeholder='Enter workspace ID to load'
                value={loadWorkspaceId}
                onChange={(e) => setLoadWorkspaceId(e.target.value)}
                className='w-full rounded border border-border-secondary p-3'
              />
              <p className='mt-1 text-xs text-gray-500'>
                Enter the ID of an existing workspace to load its progress and
                continue from where you left off
              </p>
            </div>

            <button
              onClick={() => loadWorkspaceMutation.mutate(loadWorkspaceId)}
              disabled={
                loadWorkspaceMutation.isPending || !loadWorkspaceId.trim()
              }
              className='bg-accent-primary hover:bg-accent-primary/80 rounded px-6 py-3 text-white transition-colors disabled:cursor-not-allowed disabled:opacity-50'
            >
              {loadWorkspaceMutation.isPending
                ? 'Loading Workspace...'
                : 'Load Workspace'}
            </button>

            {loadWorkspaceMutation.error && (
              <div className='rounded-lg border border-red-200 bg-red-50 p-4'>
                <p className='text-sm text-red-800'>
                  Error: {(loadWorkspaceMutation.error as any).message}
                </p>
              </div>
            )}

            {workspaceId && (
              <div className='bg-grass-50 rounded-lg border border-grass-200 p-4'>
                <h4 className='mb-2 text-sm font-medium text-grass-800'>
                  Workspace Loaded Successfully
                </h4>
                <div className='space-y-2'>
                  <div className='flex items-center gap-2'>
                    <span className='text-xs font-medium text-grass-700'>
                      Workspace ID:
                    </span>
                    <code className='rounded border px-2 py-1 text-xs'>
                      {workspaceId}
                    </code>
                  </div>
                  {clipId && (
                    <div className='flex items-center gap-2'>
                      <span className='text-xs font-medium text-grass-700'>
                        Clip ID:
                      </span>
                      <code className='rounded border px-2 py-1 text-xs'>
                        {clipId}
                      </code>
                    </div>
                  )}
                  {customReferenceId && (
                    <div className='flex items-center gap-2'>
                      <span className='text-xs font-medium text-grass-700'>
                        Custom Reference:
                      </span>
                      <code className='rounded border px-2 py-1 text-xs'>
                        {customReferenceId}
                      </code>
                    </div>
                  )}
                  {imageUrl && (
                    <div className='flex items-center gap-2'>
                      <span className='text-xs font-medium text-grass-700'>
                        Image Reference:
                      </span>
                      <code className='max-w-48 overflow-hidden rounded border px-2 py-1 text-xs text-ellipsis'>
                        {imageUrl}
                      </code>
                    </div>
                  )}
                </div>
                {workspaceData && (
                  <div className='mt-2 flex items-center gap-2'>
                    <span className='text-xs font-medium text-grass-700'>
                      Status:
                    </span>
                    <span className='rounded bg-gray-100 px-2 py-1 text-xs font-medium'>
                      {workspaceData.status}
                    </span>
                  </div>
                )}
                <p className='mt-2 text-xs text-grass-600'>
                  You can now continue working with this workspace using the
                  Generate Video tab.
                </p>
              </div>
            )}
          </div>
        )}
      </div>

      <div className='space-y-6'>
        {steps.map((step, _index) => (
          <div
            key={step.id}
            className='rounded-lg border border-border-primary p-6'
          >
            <div className='flex items-start gap-4'>
              <div
                className={twMerge(
                  'flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full border-2 text-lg font-medium',
                  getStatusColor(step.status)
                )}
              >
                {step.status === 'running' ? (
                  <div className='h-5 w-5 animate-spin rounded-full border-2 border-current border-t-transparent' />
                ) : (
                  getStatusIcon(step.status)
                )}
              </div>

              <div className='min-w-0 flex-1'>
                <div className='mb-2 flex items-center justify-between'>
                  <h3 className='text-lg font-semibold text-foreground-primary'>
                    {step.name}
                  </h3>
                  <span
                    className={twMerge(
                      'rounded-full border px-3 py-1 text-sm capitalize',
                      getStatusColor(step.status)
                    )}
                  >
                    {step.status}
                  </span>
                </div>

                <p className='mb-4 text-foreground-secondary'>
                  {step.description}
                </p>

                {renderStepActions(step)}
                {renderStepOutput(step)}
              </div>
            </div>
          </div>
        ))}
      </div>

      {workspaceData?.video_url && (
        <div className='bg-grass-50 mt-8 rounded-lg border-2 border-grass-200 p-6'>
          <h3 className='mb-4 text-lg font-semibold text-grass-800'>
            Video Generation Complete
          </h3>
          <div className='space-y-4'>
            <div className='aspect-video max-w-2xl overflow-hidden rounded-lg bg-black'>
              <video
                src={workspaceData.video_url}
                className='h-full w-full'
                controls
              />
            </div>
            <a
              href={workspaceData.video_url}
              target='_blank'
              rel='noopener noreferrer'
              className='inline-block rounded-lg bg-grass-600 px-6 py-3 text-white transition-colors hover:bg-grass-700'
            >
              Download Video
            </a>
          </div>
        </div>
      )}
    </div>
  );
};

export default VideoGenClient;
