// TODO: I moved the sample timeline data to a dedicated file, and delayed the loading to 1 sec with useEffect. as such, alot of the ogics are broken. I need to make sure the delayed timeline should work like normal

/**
 * ========================================
 * VIDEO EDITOR SYSTEM ARCHITECTURE OVERVIEW
 * ========================================
 *
 * This VideoEditor component is the core orchestrator of a multi-video timeline editing system.
 * It manages synchronized playback of multiple video elements with precise timing control.
 *
 * SYSTEM FLOW:
 *
 * 1. INITIALIZATION PHASE:
 *    - Loads timeline data (delayed by 1s to simulate async loading)
 *    - Creates HTML video elements for each timeline video with multiple source formats
 *    - Loads poster images and calculates optimal scaling/positioning for canvas
 *    - Sets up cross-component event communication via MittContext
 *
 * 2. VIDEO SETUP PHASE:
 *    - For each video: creates <video> element with WebM + MOV sources for browser compatibility
 *    - Loads poster images to determine video dimensions and calculate centered positioning
 *    - Attaches event listeners for metadata loading and error handling
 *    - Updates timeline elements with positioning data and video element references
 *
 * 3. PLAYBACK CONTROL SYSTEM:
 *    - Animation loop runs at ~60fps using requestAnimationFrame
 *    - Updates throttled to ~20fps (0.05s intervals) for performance optimization
 *    - Calculates elapsed time from playback start + paused time offset
 *    - Synchronizes all video elements to match timeline position
 *    - Handles video trimming via inPoint offsets for precise start times
 *
 * 4. VIDEO SYNCHRONIZATION:
 *    - Determines which videos should be active at current timeline position
 *    - Plays/pauses individual videos based on their timeline segments
 *    - Manages audio muting to prevent overlapping audio tracks
 *    - Updates video currentTime with threshold-based seeking to avoid excessive operations
 *
 * 5. STATE MANAGEMENT:
 *    - Local state for timeline position, playback status, video elements
 *    - Global state sync via VideoEditorStore for cross-component coordination
 *    - Event-driven communication for play/pause/seek operations from UI controls
 *    - Loading progress tracking for user feedback during video initialization
 *
 * 6. PERFORMANCE OPTIMIZATIONS:
 *    - useCallback for stable function references to prevent unnecessary re-renders
 *    - Ref-based timing to avoid state dependency loops in animation
 *    - Throttled updates to balance smooth playback with performance
 *    - Cleanup functions to prevent memory leaks from video elements and event listeners
 *
 * 7. EXPORT INTEGRATION:
 *    - Integrates with useVideoExport hook for FFmpeg-based video rendering
 *    - Passes timeline data, dimensions, and duration for export processing
 *    - Provides export progress and status feedback to user interface
 *
 * KEY ARCHITECTURAL DECISIONS:
 * - Separation of concerns: VideoEditor (logic) + VideoPreview (presentation)
 * - Event-driven communication for loose coupling between components
 * - HTML video elements for browser-native video handling and performance
 * - Multiple source formats (WebM/MOV) for maximum browser compatibility
 * - Poster-based sizing to ensure consistent layout before video metadata loads
 * - Ref-based animation timing to avoid React state update performance issues
 *
 * TIMELINE ELEMENT STRUCTURE:
 * Each timeline element contains: id, type, startTime, duration, inPoint, source files,
 * positioning data (x, y, width, height), and runtime references (videoElement, posterImage)
 */

// Import dependencies for event communication, state management, React hooks, and child components
import { useMitt } from '@/plugins/MittContext'; // Event emitter for cross-component communication
import useVideoEditorStore from '@/stores/VideoEditorStore'; // Global state store for video editor
import { useCallback, useEffect, useRef, useState } from 'react'; // React hooks for state and lifecycle management
import sampleTimelineElements from './sample-timeline-data'; // Sample timeline data for testing/demo
import useVideoExport from './video-export'; // Custom hook for video export functionality
import VideoPreview from './video-preview'; // Child component that renders the actual video preview

/**
 * VideoEditor - Main component that orchestrates video editing functionality
 * Manages timeline elements, video playback, synchronization, and export
 * @param {number} width - Canvas width for video rendering
 * @param {number} height - Canvas height for video rendering
 */
const VideoEditor = ({ width, height }) => {
    // Canvas dimensions - immutable once set, used for video scaling and positioning
    const [dimensions] = useState({
        width: width,
        height: height,
    });

    // Timeline elements array - contains all video/audio/text elements with timing and positioning data
    // Each element has: id, type, startTime, duration, source files, positioning, etc.
    const [timelineElements, setTimelineElements] = useState([]);

    // Performance optimization - tracks last animation frame update time to throttle rendering
    const lastUpdateRef = useRef(0);
    // Event emitter instance for cross-component communication (play, pause, seek events)
    const emitter = useMitt();

    // Current playback time in seconds - drives the entire timeline synchronization
    const [currentTime, setCurrentTime] = useState(0);
    // Playback state - controls animation loop and video element play/pause
    const [isPlaying, setIsPlaying] = useState(false);
    // Dictionary of HTML video elements keyed by timeline element ID
    const [videoElements, setVideoElements] = useState({});
    // Set tracking which video elements have finished loading (for UI feedback)
    const [loadedVideos, setLoadedVideos] = useState(new Set());
    // Status message for user feedback during loading/playback
    const [status, setStatus] = useState('Loading videos...');
    // Tracks which video elements should be playing at current time (optimization)
    const [videoStates, setVideoStates] = useState({});

    // Reference to the animation loop controller for cleanup
    const animationRef = useRef(null);
    // Reference to Konva layer for manual redraw triggering
    const layerRef = useRef(null);
    // Timestamp when playback started (for calculating elapsed time)
    const startTimeRef = useRef(0);
    // Time when playback was paused (for resuming from correct position)
    const pausedTimeRef = useRef(0);

    // Global state setter to sync playing state across the application
    const { setVideoIsPlaying } = useVideoEditorStore();

    // INITIALIZATION EFFECT: Load sample timeline data with 1 second delay
    // This simulates async data loading and tests the component's ability to handle delayed timeline setup
    useEffect(() => {
        setTimeout(() => setTimelineElements(sampleTimelineElements), 1000);
    }, []);

    // GLOBAL STATE SYNC EFFECT: Keep global video playing state in sync with local state
    // This allows other components to know when video is playing for UI updates
    useEffect(() => {
        setVideoIsPlaying(isPlaying);
    }, [isPlaying, setVideoIsPlaying]);

    // Calculate total timeline duration by finding the element that ends latest
    // Used for progress bars, seek limits, and auto-stop functionality
    const totalDuration = Math.max(...timelineElements.map((el) => el.startTime + el.duration));

    // VIDEO EXPORT INTEGRATION: Custom hook that handles FFmpeg-based video export
    // Provides export state, progress tracking, and export functions
    const { isExporting, exportProgress, exportStatus, ffmpegCommand, copyFFmpegCommand, exportVideo } = useVideoExport({
        timelineElements, // Timeline data for export processing
        dimensions, // Canvas dimensions for output video
        totalDuration, // Total duration for export progress calculation
    });

    // VIDEO ELEMENTS SETUP EFFECT: Creates and configures HTML video elements for each timeline video
    // This is a complex effect that handles video loading, poster image scaling, and element positioning
    useEffect(() => {
        const videoEls = {}; // Local dictionary to store video elements before setting state
        // Filter timeline to get only video elements (excludes text, audio, etc.)
        const videoElementsData = timelineElements.filter((el) => el.type === 'video');

        videoElementsData.forEach((element) => {
            // Create HTML video element with optimal settings for timeline playback
            const video = document.createElement('video');
            video.crossOrigin = 'anonymous'; // Allow cross-origin video loading
            video.muted = true; // Start muted to avoid autoplay restrictions
            video.preload = 'metadata'; // Load metadata only to save bandwidth
            video.playsInline = true; // Prevent fullscreen on mobile
            video.controls = false; // Hide native video controls

            // Add multiple video sources for browser compatibility
            // WebM source with VP9 codec (modern browsers, better compression)
            const sourceWebM = document.createElement('source');
            sourceWebM.src = element.source_webm;
            sourceWebM.type = 'video/webm; codecs=vp09.00.41.08';

            // MOV source with HEVC codec (Safari, high quality)
            const sourceMov = document.createElement('source');
            sourceMov.src = element.source_mov;
            sourceMov.type = 'video/quicktime; codecs=hvc1.1.6.H120.b0';

            // Add sources to video element (browser will choose best supported format)
            video.appendChild(sourceMov);
            video.appendChild(sourceWebM);

            // Load poster image for thumbnail display and size calculation
            const posterImg = new Image();
            posterImg.crossOrigin = 'anonymous'; // Allow cross-origin image loading
            posterImg.src = element.poster;

            // POSTER LOAD HANDLER: Calculate video positioning and scaling when poster loads
            posterImg.onload = () => {
                // Get canvas dimensions for scaling calculations
                const maxWidth = dimensions.width;
                const maxHeight = dimensions.height;
                const posterWidth = posterImg.naturalWidth;
                const posterHeight = posterImg.naturalHeight;

                // Initialize with original dimensions
                let scaledWidth = posterWidth;
                let scaledHeight = posterHeight;

                // Scale down if video is larger than canvas (maintain aspect ratio)
                if (posterWidth > maxWidth || posterHeight > maxHeight) {
                    const scaleX = maxWidth / posterWidth; // Horizontal scale factor
                    const scaleY = maxHeight / posterHeight; // Vertical scale factor
                    const scale = Math.min(scaleX, scaleY); // Use smaller scale to fit both dimensions

                    scaledWidth = posterWidth * scale;
                    scaledHeight = posterHeight * scale;
                }

                // Center the video within the canvas
                const centeredX = (maxWidth - scaledWidth) / 2;
                const centeredY = (maxHeight - scaledHeight) / 2;

                // Update timeline element with calculated positioning and poster data
                setTimelineElements((prev) =>
                    prev.map((el) => {
                        if (el.id === element.id && el.type === 'video') {
                            return {
                                ...el,
                                x: centeredX, // Horizontal position
                                y: centeredY, // Vertical position
                                width: scaledWidth, // Scaled width
                                height: scaledHeight, // Scaled height
                                posterImage: posterImg, // Poster image reference
                                isVideoPoster: true, // Flag indicating poster is loaded
                            };
                        }
                        return el;
                    }),
                );

                // Mark this video as loaded for progress tracking
                setLoadedVideos((prev) => {
                    const newSet = new Set(prev);
                    newSet.add(element.id);
                    return newSet;
                });
            };

            // VIDEO METADATA LOAD HANDLER: Attach video element when metadata is ready
            video.addEventListener('loadedmetadata', () => {
                setTimelineElements((prev) =>
                    prev.map((el) => {
                        if (el.id === element.id && el.type === 'video') {
                            return {
                                ...el,
                                videoElement: video, // Attach HTML video element
                                isVideoReady: true, // Flag indicating video is ready for playback
                            };
                        }
                        return el;
                    }),
                );
            });

            // ERROR HANDLERS: Log errors for debugging
            video.addEventListener('error', (e) => {
                console.error(`Error loading video ${element.id}:`, e);
            });

            posterImg.onerror = (e) => {
                console.error(`Error loading poster ${element.id}:`, e);
            };

            // Store video element in local dictionary
            videoEls[element.id] = video;
        });

        // Update state with all created video elements
        setVideoElements(videoEls);

        // CLEANUP FUNCTION: Properly dispose of video elements to prevent memory leaks
        return () => {
            Object.values(videoEls).forEach((video) => {
                video.src = ''; // Clear source to stop loading
                video.load(); // Reset video element
            });
        };
    }, []); // Empty dependency array - only run once on mount

    // LOADING STATUS EFFECT: Update status message based on video loading progress
    // Provides user feedback during the video loading process
    useEffect(() => {
        const videoCount = timelineElements.filter((el) => el.type === 'video').length;
        if (loadedVideos.size === videoCount && videoCount > 0) {
            setStatus('Ready to play'); // All videos loaded
        } else if (videoCount > 0) {
            setStatus(`Loading videos... (${loadedVideos.size}/${videoCount})`); // Show progress
        } else {
            setStatus('Ready to play'); // No videos to load
        }
    }, [loadedVideos, timelineElements]);

    // PAUSE HANDLER: Stops playback and pauses all video elements
    // FIXED: Removed currentTime dependency to prevent excessive recreation
    const handlePause = useCallback(() => {
        if (isPlaying) {
            setIsPlaying(false); // Update playback state
            pausedTimeRef.current = currentTime; // Store current time for resume

            // Pause all video elements and mute them
            Object.values(videoElements).forEach((video) => {
                if (!video.paused) {
                    video.pause(); // Pause video playback
                }
                video.muted = true; // Mute to prevent audio overlap
            });

            setVideoStates({}); // Clear video states

            // Stop animation loop
            if (animationRef.current) {
                animationRef.current.stop();
                animationRef.current = null;
            }
        }
    }, [isPlaying, videoElements]);

    // ACTIVE ELEMENTS CALCULATOR: Determines which timeline elements should be visible at given time
    // Used for rendering optimization - only process elements that are currently active
    const getActiveElements = useCallback(
        (time) => {
            return timelineElements.filter((element) => {
                const elementEndTime = element.startTime + element.duration;
                // Element is active if current time is within its start and end time
                return time >= element.startTime && time < elementEndTime;
            });
        },
        [timelineElements],
    );

    // VIDEO STATES CALCULATOR: Determines which videos should be playing at given time
    // Returns object mapping video IDs to boolean play states for synchronization
    const getDesiredVideoStates = useCallback(
        (time) => {
            const states = {};
            timelineElements.forEach((element) => {
                if (element.type === 'video') {
                    const elementEndTime = element.startTime + element.duration;
                    // Video should play if current time is within its timeline segment
                    states[element.id] = time >= element.startTime && time < elementEndTime;
                }
            });
            return states;
        },
        [timelineElements],
    );

    // VIDEO TIME SYNCHRONIZER: Updates individual video currentTime to match timeline position
    // Handles video trimming (inPoint) and prevents excessive seeking with threshold
    const updateVideoTimes = useCallback(
        (time) => {
            timelineElements.forEach((element) => {
                if (element.type === 'video' && videoElements[element.id]) {
                    const video = videoElements[element.id];
                    const elementEndTime = element.startTime + element.duration;

                    // Only update videos that are currently active on timeline
                    if (time >= element.startTime && time < elementEndTime) {
                        // Calculate relative time within the element's duration
                        const relativeTime = time - element.startTime;
                        // Add inPoint offset for trimmed videos (start from specific time in source)
                        const videoTime = element.inPoint + relativeTime;

                        // Only seek if difference is significant (>0.5s) to avoid excessive seeking
                        if (Math.abs(video.currentTime - videoTime) > 0.5) {
                            video.currentTime = videoTime;
                        }
                    }
                }
            });
        },
        [timelineElements, videoElements],
    );

    // VIDEO PLAYBACK SYNCHRONIZATION EFFECT: Manages play/pause state of individual videos
    // Ensures only videos that should be active at current time are playing
    useEffect(() => {
        if (!isPlaying) return; // Skip if timeline is paused

        // Get which videos should be playing at current time
        const desiredStates = getDesiredVideoStates(currentTime);

        // Synchronize each video's play state with desired state
        Object.entries(desiredStates).forEach(([videoId, shouldPlay]) => {
            const video = videoElements[videoId];
            const isCurrentlyPlaying = !video?.paused;

            if (video) {
                if (shouldPlay && !isCurrentlyPlaying) {
                    // Start playing: unmute and play
                    video.muted = false;
                    video.play().catch((e) => console.warn('Video play failed:', e));
                } else if (!shouldPlay && isCurrentlyPlaying) {
                    // Stop playing: pause and mute
                    video.pause();
                    video.muted = true;
                }
            }
        });

        // Update video states for UI feedback
        setVideoStates(desiredStates);
    }, [currentTime, isPlaying, videoElements, getDesiredVideoStates]);

    // ANIMATION LOOP EFFECT: Main playback engine that drives timeline progression
    // FIXED: Properly stop animation when not playing
    useEffect(() => {
        // Stop any existing animation when not playing
        if (!isPlaying) {
            if (animationRef.current) {
                animationRef.current.stop();
                animationRef.current = null;
            }
            return;
        }

        let animationId; // RequestAnimationFrame ID for cleanup
        let isRunning = true; // Flag to control animation loop

        // ANIMATION FRAME FUNCTION: Called ~60fps to update timeline
        const animateFrame = () => {
            if (!isRunning) return; // Exit if animation was stopped

            // Calculate elapsed time since playback started
            const now = Date.now() / 1000;
            const newTime = pausedTimeRef.current + (now - startTimeRef.current);

            // Auto-stop and reset when reaching end of timeline
            if (newTime >= totalDuration) {
                handlePause();
                handleSeek(0);
                return;
            }

            // Throttle updates to ~20fps (0.05s intervals) for performance
            if (newTime - lastUpdateRef.current >= 0.05) {
                lastUpdateRef.current = newTime;
                setCurrentTime(newTime); // Update timeline position
                updateVideoTimes(newTime); // Sync video elements

                // Trigger Konva layer redraw for visual updates
                if (layerRef.current) {
                    layerRef.current.batchDraw();
                }
            }

            // Schedule next frame if still running
            if (isRunning) {
                animationId = requestAnimationFrame(animateFrame);
            }
        };

        // Initialize animation timing and start loop
        startTimeRef.current = Date.now() / 1000;
        animationId = requestAnimationFrame(animateFrame);

        // Create animation controller for external stop capability
        animationRef.current = {
            stop: () => {
                isRunning = false;
                if (animationId) {
                    cancelAnimationFrame(animationId);
                }
            },
        };

        // CLEANUP: Stop animation when effect unmounts or dependencies change
        return () => {
            isRunning = false;
            if (animationId) {
                cancelAnimationFrame(animationId);
            }
        };
    }, [isPlaying, totalDuration, handlePause, updateVideoTimes]);

    // PLAY HANDLER: Starts timeline playback from current position
    // FIXED: Stabilized handlers to prevent unnecessary re-renders
    const handlePlay = useCallback(() => {
        if (!isPlaying) {
            setIsPlaying(true); // Trigger animation loop
            startTimeRef.current = Date.now() / 1000; // Record start time for elapsed calculation
            lastUpdateRef.current = 0; // Reset update throttling
            setStatus(''); // Clear status message during playback
        }
    }, [isPlaying]);

    // SEEK HANDLER: Jumps to specific time position on timeline
    const handleSeek = useCallback(
        (time) => {
            // Clamp time to valid range [0, totalDuration]
            const clampedTime = Math.max(0, Math.min(time, totalDuration));
            setCurrentTime(clampedTime); // Update timeline position
            pausedTimeRef.current = clampedTime; // Update pause reference for resume
            updateVideoTimes(clampedTime); // Sync all video elements to new time

            setVideoStates({}); // Clear video states to force recalculation

            // Trigger immediate visual update for seek feedback
            if (layerRef.current) {
                layerRef.current.draw();
            }
        },
        [totalDuration, updateVideoTimes],
    );

    // RESET HANDLER: Stops playback and returns to beginning of timeline
    const handleReset = useCallback(() => {
        handlePause(); // Stop playback
        handleSeek(0); // Jump to start of timeline
        lastUpdateRef.current = 0; // Reset animation throttling

        // Ensure all videos are muted after reset
        Object.values(videoElements).forEach((video) => {
            video.muted = true;
        });
    }, [handlePause, handleSeek, videoElements]);

    // Get elements that should be visible/active at current timeline position
    // Used by VideoPreview component for rendering decisions
    const activeElements = getActiveElements(currentTime);

    // EVENT LISTENERS EFFECT: Subscribe to cross-component video control events
    // FIXED: Added missing dependencies to event listeners
    useEffect(() => {
        // Subscribe to events from other components (timeline controls, keyboard shortcuts, etc.)
        emitter.on('video-play', handlePlay); // Play button clicked
        emitter.on('video-reset', handleReset); // Reset button clicked
        emitter.on('video-seek', handleSeek); // Timeline scrubber moved

        // CLEANUP: Unsubscribe from events to prevent memory leaks
        return () => {
            emitter.off('video-play', handlePlay);
            emitter.off('video-reset', handleReset);
            emitter.off('video-seek', handleSeek);
        };
    }, [emitter, handlePlay, handleReset, handleSeek]);

    // COMPONENT RENDER: Return the video editor UI wrapped in a container
    return (
        <div style={{ width: dimensions.width, height: dimensions.height }} className="rounded-3xl">
            {/*
                VideoPreview Component - Handles the actual video rendering and UI
                Receives all state, handlers, and data needed for video preview functionality
                This separation allows VideoEditor to focus on logic while VideoPreview handles presentation
            */}
            <VideoPreview
                // Canvas and timing props
                dimensions={dimensions} // Canvas width/height for rendering
                currentTime={currentTime} // Current playback position
                totalDuration={totalDuration} // Total timeline duration
                isPlaying={isPlaying} // Playback state
                status={status} // Loading/status message
                // Export-related props
                isExporting={isExporting} // Export in progress flag
                exportProgress={exportProgress} // Export progress percentage
                exportStatus={exportStatus} // Export status message
                ffmpegCommand={ffmpegCommand} // Generated FFmpeg command
                copyFFmpegCommand={copyFFmpegCommand} // Function to copy command
                exportVideo={exportVideo} // Function to start export
                // Timeline and video data
                timelineElements={timelineElements} // All timeline elements
                activeElements={activeElements} // Currently visible elements
                videoElements={videoElements} // HTML video element references
                loadedVideos={loadedVideos} // Set of loaded video IDs
                videoStates={videoStates} // Current video play states
                // Control handlers
                handlePlay={handlePlay} // Start playback
                handlePause={handlePause} // Pause playback
                handleReset={handleReset} // Reset to beginning
                handleSeek={handleSeek} // Seek to specific time
                // Rendering reference
                layerRef={layerRef} // Konva layer reference for manual redraws
            />
        </div>
    );
};

export default VideoEditor;
