import { useEffect, useRef, useState, useCallback } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from './useAuth'; interface UseVideoProgressOptions { videoId: string; videoType: 'lesson' | 'webinar'; duration?: number; onSaveInterval?: number; // seconds, default 5 } interface VideoProgress { last_position: number; total_duration?: number; completed: boolean; last_watched_at: string; } export const useVideoProgress = ({ videoId, videoType, duration, onSaveInterval = 5, }: UseVideoProgressOptions) => { const { user } = useAuth(); const [progress, setProgress] = useState(null); const [loading, setLoading] = useState(true); const lastSavedPosition = useRef(0); const saveTimeoutRef = useRef(null); const userRef = useRef(user); const videoIdRef = useRef(videoId); const videoTypeRef = useRef(videoType); const durationRef = useRef(duration); // Update refs when props change useEffect(() => { userRef.current = user; videoIdRef.current = videoId; videoTypeRef.current = videoType; durationRef.current = duration; }, [user, videoId, videoType, duration]); // Load existing progress useEffect(() => { if (!user || !videoId) { setLoading(false); return; } const loadProgress = async () => { const { data, error } = await supabase .from('video_progress') .select('*') .eq('user_id', user.id) .eq('video_id', videoId) .eq('video_type', videoType) .maybeSingle(); if (error) { console.error('Error loading video progress:', error); } else if (data) { setProgress(data); lastSavedPosition.current = data.last_position; } setLoading(false); }; loadProgress(); }, [user, videoId, videoType]); // Save progress directly (not debounced for reliability) const saveProgress = useCallback(async (position: number) => { const currentUser = userRef.current; const currentVideoId = videoIdRef.current; const currentVideoType = videoTypeRef.current; const currentDuration = durationRef.current; if (!currentUser || !currentVideoId) return; // Don't save if position hasn't changed significantly (less than 1 second) if (Math.abs(position - lastSavedPosition.current) < 1) return; const completed = currentDuration ? position / currentDuration >= 0.95 : false; const { error } = await supabase .from('video_progress') .upsert( { user_id: currentUser.id, video_id: currentVideoId, video_type: currentVideoType, last_position: position, total_duration: currentDuration, completed, }, { onConflict: 'user_id,video_id,video_type', } ); if (error) { console.error('Error saving video progress:', error); } else { lastSavedPosition.current = position; } }, []); // Empty deps - uses refs internally // Save on unmount useEffect(() => { return () => { if (saveTimeoutRef.current) { clearTimeout(saveTimeoutRef.current); } // Save final position if (lastSavedPosition.current > 0) { saveProgress(lastSavedPosition.current); } }; }, [saveProgress]); return { progress, loading, saveProgress, // Return the direct save function hasProgress: progress !== null && progress.last_position > 5, // Only show if more than 5 seconds watched }; };