/**
 * Progressive Loading Hook for Canvas
 * 
 * Implements progressive loading strategy to improve canvas loading performance:
 * - Stage 1: Load canvas structure (node positions, connections)
 * - Stage 2: Load node content (images, videos)
 * - Stage 3: Complete
 * 
 * This approach allows the canvas to render quickly with placeholders,
 * then progressively load heavy content in the background.
 */

import { useState, useEffect, useCallback } from 'react';
import { AppNodeType } from '../types/node';
import { Edge } from '@xyflow/react';
import { loadCanvasStateFromStorage } from '../services/storage';
import { canvasCache } from '@/lib/utils/canvasCache';
import { CanvasMetadata } from '@/types';

/**
 * Loading stages for progressive canvas loading
 */
export type LoadingStage = 'idle' | 'structure' | 'content' | 'complete' | 'error';

/**
 * Progressive loading state
 */
export interface ProgressiveLoadingState {
  /** Current loading stage */
  stage: LoadingStage;
  /** Loading progress (0-100) */
  progress: number;
  /** Error message if loading failed */
  error?: string;
  /** Loaded canvas structure (nodes and edges) */
  structure?: {
    nodes: AppNodeType[];
    edges: Edge[];
  };
  /** Whether loading is in progress */
  isLoading: boolean;
}

/**
 * Options for progressive loading
 */
export interface ProgressiveLoadingOptions {
  /** Canvas ID to load */
  canvasId: string;
  /** Project ID (optional, for server loading) */
  projectId?: string;
  /** Canvas metadata (optional, for caching) */
  metadata?: CanvasMetadata;
  /** Whether to use cache */
  useCache?: boolean;
  /** Callback when structure is loaded */
  onStructureLoaded?: (nodes: AppNodeType[], edges: Edge[]) => void;
  /** Callback when content is loaded */
  onContentLoaded?: (nodes: AppNodeType[], edges: Edge[]) => void;
  /** Callback when loading is complete */
  onComplete?: () => void;
  /** Callback when loading fails */
  onError?: (error: Error) => void;
}

/**
 * Hook for progressive canvas loading
 * 
 * @example
 * ```typescript
 * const { stage, progress, structure, isLoading } = useProgressiveLoading({
 *   canvasId: 'canvas-123',
 *   projectId: 'project-456',
 *   onStructureLoaded: (nodes, edges) => {
 *     setNodes(nodes);
 *     setEdges(edges);
 *   },
 *   onContentLoaded: (nodes, edges) => {
 *     setNodes(nodes);
 *     setEdges(edges);
 *   }
 * });
 * ```
 */
export function useProgressiveLoading(options: ProgressiveLoadingOptions) {
  const {
    canvasId,
    projectId,
    metadata,
    useCache = true,
    onStructureLoaded,
    onContentLoaded,
    onComplete,
    onError,
  } = options;

  const [state, setState] = useState<ProgressiveLoadingState>({
    stage: 'idle',
    progress: 0,
    isLoading: false,
  });

  /**
   * Load canvas structure (node positions and connections only)
   */
  const loadCanvasStructure = useCallback(async (
    canvasId: string,
    projectId?: string,
    metadata?: CanvasMetadata
  ): Promise<{ nodes: AppNodeType[]; edges: Edge[] }> => {
    try {
      // Load full canvas state
      const canvasState = await loadCanvasStateFromStorage<{
        nodes: AppNodeType[];
        edges: Edge[];
        history?: any[];
      }>(canvasId, projectId, metadata);

      if (!canvasState) {
        return { nodes: [], edges: [] };
      }

      // Extract structure (strip heavy content from nodes)
      const structureNodes = canvasState.nodes.map((node) => {
        // Handle group nodes (they don't have heavy content)
        if ((node as any).type === 'group') {
          return node;
        }

        // Handle app nodes - strip heavy content
        return {
          ...node,
          data: {
            ...node.data,
            // Keep essential data, remove heavy content
            image: undefined,
            images: undefined,
            videoUri: undefined,
            videoUris: undefined,
            audioUri: undefined,
            content: (node.data as any).content ? '[Loading...]' : undefined,
          },
        } as AppNodeType;
      });

      return {
        nodes: structureNodes,
        edges: canvasState.edges,
      };
    } catch (error) {
      console.error('[ProgressiveLoading] Failed to load canvas structure:', error);
      throw error;
    }
  }, []);

  /**
   * Load canvas content (images, videos, etc.)
   */
  const loadCanvasContent = useCallback(async (
    canvasId: string,
    projectId?: string,
    metadata?: CanvasMetadata
  ): Promise<{ nodes: AppNodeType[]; edges: Edge[] }> => {
    try {
      // Load full canvas state with all content
      const canvasState = await loadCanvasStateFromStorage<{
        nodes: AppNodeType[];
        edges: Edge[];
        history?: any[];
      }>(canvasId, projectId, metadata);

      if (!canvasState) {
        return { nodes: [], edges: [] };
      }

      return {
        nodes: canvasState.nodes,
        edges: canvasState.edges,
      };
    } catch (error) {
      console.error('[ProgressiveLoading] Failed to load canvas content:', error);
      throw error;
    }
  }, []);

  /**
   * Main loading function
   */
  const loadCanvas = useCallback(async () => {
    if (!canvasId) {
      return;
    }

    setState({
      stage: 'idle',
      progress: 0,
      isLoading: true,
    });

    try {
      // Check cache first
      if (useCache) {
        const cached = canvasCache.get(canvasId);
        if (cached) {
          console.log('[ProgressiveLoading] Cache hit for canvas:', canvasId);
          
          setState({
            stage: 'complete',
            progress: 100,
            structure: cached.content,
            isLoading: false,
          });

          // Notify callbacks
          if (onStructureLoaded) {
            onStructureLoaded(cached.content.nodes, cached.content.edges);
          }
          if (onContentLoaded) {
            onContentLoaded(cached.content.nodes, cached.content.edges);
          }
          if (onComplete) {
            onComplete();
          }

          return;
        }
      }

      // Stage 1: Load structure (30% progress)
      setState({
        stage: 'structure',
        progress: 10,
        isLoading: true,
      });

      const structure = await loadCanvasStructure(canvasId, projectId, metadata);

      setState({
        stage: 'structure',
        progress: 30,
        structure,
        isLoading: true,
      });

      // Notify structure loaded
      if (onStructureLoaded) {
        onStructureLoaded(structure.nodes, structure.edges);
      }

      // Stage 2: Load content (60% progress)
      setState((prev) => ({
        ...prev,
        stage: 'content',
        progress: 50,
      }));

      const content = await loadCanvasContent(canvasId, projectId, metadata);

      setState((prev) => ({
        ...prev,
        stage: 'content',
        progress: 80,
        structure: content,
      }));

      // Notify content loaded
      if (onContentLoaded) {
        onContentLoaded(content.nodes, content.edges);
      }

      // Stage 3: Complete (100% progress)
      setState({
        stage: 'complete',
        progress: 100,
        structure: content,
        isLoading: false,
      });

      // Cache the loaded canvas
      if (useCache && metadata) {
        canvasCache.set(canvasId, {
          metadata,
          content,
        });
      }

      // Notify complete
      if (onComplete) {
        onComplete();
      }
    } catch (error) {
      console.error('[ProgressiveLoading] Canvas loading failed:', error);
      
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      
      setState({
        stage: 'error',
        progress: 0,
        error: errorMessage,
        isLoading: false,
      });

      // Notify error
      if (onError) {
        onError(error instanceof Error ? error : new Error(errorMessage));
      }
    }
  }, [
    canvasId,
    projectId,
    metadata,
    useCache,
    loadCanvasStructure,
    loadCanvasContent,
    onStructureLoaded,
    onContentLoaded,
    onComplete,
    onError,
  ]);

  // Trigger loading when canvasId changes
  useEffect(() => {
    if (canvasId) {
      loadCanvas();
    }
  }, [canvasId, loadCanvas]);

  return {
    ...state,
    reload: loadCanvas,
  };
}

/**
 * Helper function to create placeholder nodes for loading state
 */
export function createPlaceholderNode(node: AppNodeType): AppNodeType {
  // Handle group nodes (they don't need placeholders)
  if ((node as any).type === 'group') {
    return node;
  }

  // Handle app nodes - create placeholder
  return {
    ...node,
    data: {
      ...node.data,
      status: 'IDLE',
      image: undefined,
      images: undefined,
      videoUri: undefined,
      videoUris: undefined,
      audioUri: undefined,
      content: (node.data as any).content ? '[Loading...]' : undefined,
    },
  } as AppNodeType;
}

/**
 * Helper function to check if a node has heavy content
 */
export function hasHeavyContent(node: AppNodeType): boolean {
  // Group nodes don't have heavy content
  if ((node as any).type === 'group') {
    return false;
  }

  const data = node.data as any;
  return !!(
    data.image ||
    data.images?.length ||
    data.videoUri ||
    data.videoUris?.length ||
    data.audioUri
  );
}

/**
 * Helper function to estimate content loading time
 */
export function estimateLoadingTime(nodes: AppNodeType[]): number {
  let heavyContentCount = 0;
  
  nodes.forEach((node) => {
    // Skip group nodes
    if ((node as any).type === 'group') {
      return;
    }

    const data = node.data as any;
    if (data.image) heavyContentCount++;
    if (data.images) heavyContentCount += data.images.length;
    if (data.videoUri) heavyContentCount += 2; // Videos are heavier
    if (data.videoUris) heavyContentCount += data.videoUris.length * 2;
    if (data.audioUri) heavyContentCount++;
  });

  // Estimate: 200ms per heavy content item
  return heavyContentCount * 200;
}
