import { useState, useEffect, useRef, useCallback } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { toast } from 'sonner';
import { getErrorMessage } from '@/lib/errorHandler';
import type { EntityType, EntityVersion } from '@/types/versioning';
import { logger } from '@/lib/logger';

interface FieldChange {
  id: string;
  field_name: string;
  old_value: any;
  new_value: any;
  change_type: 'added' | 'modified' | 'removed';
  created_at: string;
}

/**
 * Hook to manage entity versions using relational version tables
 * NO JSONB - Pure relational structure for type safety and queryability
 */
export function useEntityVersions(entityType: EntityType, entityId: string) {
  const [versions, setVersions] = useState<EntityVersion[]>([]);
  const [currentVersion, setCurrentVersion] = useState<EntityVersion | null>(null);
  const [loading, setLoading] = useState(true);
  const [fieldHistory, setFieldHistory] = useState<FieldChange[]>([]);
  
  const isMountedRef = useRef(true);
  const channelRef = useRef<ReturnType<typeof supabase.channel> | null>(null);
  const requestCounterRef = useRef(0);
  const fieldHistoryRequestCounterRef = useRef(0);

  const fetchVersions = useCallback(async () => {
    if (!isMountedRef.current) return;
    
    const currentRequestId = ++requestCounterRef.current;
    
    try {
      if (isMountedRef.current && currentRequestId === requestCounterRef.current) {
        setLoading(true);
      }
      
      // Build table and column names
      const versionTable = `${entityType}_versions`;
      const entityIdCol = `${entityType}_id`;
      
      let data, error;
      
      // Use explicit conditional branches for type safety
      if (entityType === 'park') {
        const result = await supabase
          .from('park_versions')
          .select(`*, profiles:created_by(username, display_name, avatar_url)`)
          .eq('park_id', entityId)
          .order('version_number', { ascending: false });
        data = result.data;
        error = result.error;
      } else if (entityType === 'ride') {
        const result = await supabase
          .from('ride_versions')
          .select(`*, profiles:created_by(username, display_name, avatar_url)`)
          .eq('ride_id', entityId)
          .order('version_number', { ascending: false });
        data = result.data;
        error = result.error;
      } else if (entityType === 'company') {
        const result = await supabase
          .from('company_versions')
          .select(`*, profiles:created_by(username, display_name, avatar_url)`)
          .eq('company_id', entityId)
          .order('version_number', { ascending: false });
        data = result.data;
        error = result.error;
      } else {
        const result = await supabase
          .from('ride_model_versions')
          .select(`*, profiles:created_by(username, display_name, avatar_url)`)
          .eq('ride_model_id', entityId)
          .order('version_number', { ascending: false });
        data = result.data;
        error = result.error;
      }

      if (error) throw error;

      if (!isMountedRef.current || currentRequestId !== requestCounterRef.current) return;

      if (!Array.isArray(data)) {
        if (isMountedRef.current && currentRequestId === requestCounterRef.current) {
          setVersions([]);
          setCurrentVersion(null);
          setLoading(false);
        }
        return;
      }

      const versionsWithProfiles = (data || []).map((v: any) => ({
        ...v,
        profiles: v.profiles || {
          username: 'Unknown',
          display_name: 'Unknown',
          avatar_url: null
        }
      })) as EntityVersion[];

      if (isMountedRef.current && currentRequestId === requestCounterRef.current) {
        setVersions(versionsWithProfiles);
        setCurrentVersion(versionsWithProfiles.find(v => v.is_current) || null);
        setLoading(false);
      }
    } catch (error: unknown) {
      const errorMsg = getErrorMessage(error);
      logger.error('Failed to fetch versions', { entityType, entityId, error: errorMsg });
      
      if (isMountedRef.current && currentRequestId === requestCounterRef.current) {
        toast.error(errorMsg);
        setLoading(false);
      }
    }
  }, [entityType, entityId]);

  /**
   * Field history has been removed - use version comparison instead
   * This function is kept for backward compatibility but does nothing
   * @deprecated Use compareVersions() to see field-level changes
   */
  const fetchFieldHistory = async (versionId: string) => {
    logger.warn('fetchFieldHistory is deprecated. Use compareVersions() instead for field-level changes.');
    setFieldHistory([]);
  };

  const compareVersions = async (fromVersionId: string, toVersionId: string) => {
    try {
      const { data, error } = await supabase.rpc('get_version_diff', {
        p_entity_type: entityType,
        p_from_version_id: fromVersionId,
        p_to_version_id: toVersionId
      });

      if (error) throw error;

      return data;
    } catch (error: unknown) {
      const errorMsg = getErrorMessage(error);
      logger.error('Failed to compare versions', { entityType, fromVersionId, toVersionId, error: errorMsg });
      if (isMountedRef.current) {
        toast.error(errorMsg);
      }
      return null;
    }
  };

  const rollbackToVersion = async (targetVersionId: string, reason: string) => {
    try {
      if (!isMountedRef.current) return null;
      
      const { data: userData } = await supabase.auth.getUser();
      if (!userData.user) throw new Error('Not authenticated');

      const { data, error } = await supabase.rpc('rollback_to_version', {
        p_entity_type: entityType,
        p_entity_id: entityId,
        p_target_version_id: targetVersionId,
        p_changed_by: userData.user.id,
        p_reason: reason
      });

      if (error) {
        // Check for authorization error (insufficient_privilege)
        if (error.code === '42501') {
          throw new Error('Only moderators can restore previous versions');
        }
        throw error;
      }

      if (isMountedRef.current) {
        toast.success('Successfully restored to previous version');
        await fetchVersions();
      }
      return data;
    } catch (error: unknown) {
      const errorMsg = getErrorMessage(error);
      logger.error('Failed to rollback version', { entityType, entityId, targetVersionId, error: errorMsg });
      if (isMountedRef.current) {
        toast.error('Failed to restore version', {
          description: errorMsg
        });
      }
      return null;
    }
  };

  useEffect(() => {
    if (entityType && entityId) {
      fetchVersions();
    }
  }, [entityType, entityId, fetchVersions]);

  useEffect(() => {
    if (!entityType || !entityId) return;

    if (channelRef.current) {
      try {
        supabase.removeChannel(channelRef.current);
      } catch (error: unknown) {
        logger.error('Failed to cleanup realtime subscription', { entityType, entityId, error: getErrorMessage(error) });
        console.error('Error removing previous channel:', error);
      } finally {
        channelRef.current = null;
      }
    }

    const versionTable = `${entityType}_versions`;
    const entityIdCol = `${entityType}_id`;
    
    const channel = supabase
      .channel(`${versionTable}_changes`)
      .on(
        'postgres_changes',
        {
          event: '*',
          schema: 'public',
          table: versionTable,
          filter: `${entityIdCol}=eq.${entityId}`
        },
        () => {
          if (isMountedRef.current) {
            fetchVersions();
          }
        }
      )
      .subscribe();

    channelRef.current = channel;

    return () => {
      if (channelRef.current) {
        supabase.removeChannel(channelRef.current).catch((error) => {
          logger.error('Failed to cleanup realtime subscription', { entityType, entityId, error: getErrorMessage(error) });
          console.error('Error removing channel:', error);
        });
        channelRef.current = null;
      }
    };
  }, [entityType, entityId, fetchVersions]);

  useEffect(() => {
    isMountedRef.current = true;
    
    return () => {
      isMountedRef.current = false;
    };
  }, []);

  return {
    versions,
    currentVersion,
    loading,
    fieldHistory,
    fetchVersions,
    fetchFieldHistory,
    compareVersions,
    rollbackToVersion
  };
}
