/**
 * Hook for Supabase Realtime Downloads
 * Subscribes to downloads table changes and updates UI in realtime
 * 
 * PERFORMANCE: Events are throttled/batched to prevent excessive re-renders
 * - INSERT: Called immediately (low frequency)
 * - UPDATE: Batched in 500ms windows (high frequency during downloads)
 * - DELETE: Called immediately (low frequency)
 */

import { useEffect, useCallback, useRef } from 'react';
import { RealtimeChannel } from '@supabase/supabase-js';
import { supabase } from './supabase';

// Throttle interval for UPDATE events (ms)
const UPDATE_THROTTLE_MS = 500;

export interface DownloadRecord {
  id: number;
  batch_id: string;
  ge_id: string;
  lang: string;
  file_name: string;
  file_path: string;
  mode: 'api' | 'sharing';
  status: 'pending' | 'downloading' | 'completed' | 'failed' | 'cancelled';
  destination_path: string | null;
  file_size: number | null;
  downloaded_size: number | null;
  progress_percent: number | null;
  created_at: string | null;
  started_at: string | null;
  completed_at: string | null;
  error_message: string | null;
  retry_count: number | null;
  sharing_id: string | null;
  mongodb_path: string | null;
  aria2_gid: string | null;
}

interface UseRealtimeDownloadsOptions {
  onInsert?: (record: DownloadRecord) => void;
  onUpdate?: (record: DownloadRecord) => void;
  onDelete?: (record: DownloadRecord) => void;
  /** Optional: filter by batch_id */
  batchId?: string;
}

/**
 * Subscribe to realtime changes on downloads table
 * UPDATE events are throttled to reduce re-renders during active downloads
 */
export function useRealtimeDownloads(options: UseRealtimeDownloadsOptions = {}) {
  const { onInsert, onUpdate, onDelete, batchId } = options;
  const channelRef = useRef<RealtimeChannel | null>(null);
  
  // Throttle state for UPDATE events
  const pendingUpdatesRef = useRef<Map<number, DownloadRecord>>(new Map());
  const flushTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const onUpdateRef = useRef(onUpdate);
  
  // Keep onUpdate ref current
  useEffect(() => {
    onUpdateRef.current = onUpdate;
  }, [onUpdate]);
  
  // Flush all pending updates
  const flushUpdates = useCallback(() => {
    if (pendingUpdatesRef.current.size > 0) {
      // Call onUpdate for each pending record
      pendingUpdatesRef.current.forEach(record => {
        onUpdateRef.current?.(record);
      });
      pendingUpdatesRef.current.clear();
    }
    flushTimeoutRef.current = null;
  }, []);
  
  // Queue an update (throttled)
  const queueUpdate = useCallback((record: DownloadRecord) => {
    // Store latest update for this record (overwrites previous if exists)
    pendingUpdatesRef.current.set(record.id, record);
    
    // Schedule flush if not already scheduled
    if (!flushTimeoutRef.current) {
      flushTimeoutRef.current = setTimeout(flushUpdates, UPDATE_THROTTLE_MS);
    }
  }, [flushUpdates]);

  const subscribe = useCallback(() => {
    // Unsubscribe existing channel
    if (channelRef.current) {
      channelRef.current.unsubscribe();
    }

    // Create filter if batchId provided
    const filter = batchId ? `batch_id=eq.${batchId}` : undefined;

    const channel = supabase
      .channel('downloads-changes')
      .on(
        'postgres_changes',
        {
          event: 'INSERT',
          schema: 'public',
          table: 'downloads',
          filter,
        },
        (payload) => {
          onInsert?.(payload.new as DownloadRecord);
        }
      )
      .on(
        'postgres_changes',
        {
          event: 'UPDATE',
          schema: 'public',
          table: 'downloads',
          filter,
        },
        (payload) => {
          // Throttle UPDATE events - they happen frequently during downloads
          queueUpdate(payload.new as DownloadRecord);
        }
      )
      .on(
        'postgres_changes',
        {
          event: 'DELETE',
          schema: 'public',
          table: 'downloads',
          filter,
        },
        (payload) => {
          onDelete?.(payload.old as DownloadRecord);
        }
      )
      .subscribe();

    channelRef.current = channel;

    return () => {
      channel.unsubscribe();
    };
  }, [onInsert, onDelete, batchId, queueUpdate]); // Removed onUpdate - now using ref

  useEffect(() => {
    const cleanup = subscribe();
    return () => {
      cleanup();
      // Clear any pending throttle timeout on unmount
      if (flushTimeoutRef.current) {
        clearTimeout(flushTimeoutRef.current);
        flushTimeoutRef.current = null;
      }
      // Flush any remaining updates
      pendingUpdatesRef.current.clear();
    };
  }, [subscribe]);

  return {
    /** Manually resubscribe */
    resubscribe: subscribe,
  };
}
