import { useState, useEffect, useCallback } from 'react';
import { fetchAPI } from '../services/api';

interface UsePersistentToggleOptions {
  /**
   * Unique identifier for the resource (e.g., 'openai', 'runware', 'gsc')
   */
  resourceId: string;
  
  /**
   * API endpoint pattern - will replace {id} with resourceId
   * Example: '/v1/system/settings/integrations/{id}/'
   */
  getEndpoint: string;
  
  /**
   * API endpoint pattern for saving - will replace {id} with resourceId
   * Example: '/v1/system/settings/integrations/{id}/save/'
   */
  saveEndpoint: string;
  
  /**
   * Initial enabled state (used before data loads)
   */
  initialEnabled?: boolean;
  
  /**
   * Function to extract enabled state from API response
   * Default: (data) => data?.enabled ?? false
   */
  extractEnabled?: (data: any) => boolean;
  
  /**
   * Function to build save payload
   * Default: (currentData, enabled) => ({ ...currentData, enabled })
   */
  buildPayload?: (currentData: any, enabled: boolean) => any;
  
  /**
   * Callback when toggle succeeds
   * @param enabled - The new enabled state
   * @param data - The full config data from the API
   */
  onToggleSuccess?: (enabled: boolean, data?: any) => void;
  
  /**
   * Callback when toggle fails
   */
  onToggleError?: (error: Error) => void;
  
  /**
   * Whether to load state on mount
   */
  loadOnMount?: boolean;
}

interface UsePersistentToggleReturn {
  /**
   * Current enabled state
   */
  enabled: boolean;
  
  /**
   * Toggle function - automatically persists to backend
   */
  toggle: (enabled: boolean) => Promise<void>;
  
  /**
   * Loading state (during save/load operations)
   */
  loading: boolean;
  
  /**
   * Error state
   */
  error: Error | null;
  
  /**
   * Full config data from API
   */
  data: any;
  
  /**
   * Manually refresh state from API
   */
  refresh: () => Promise<void>;
}

/**
 * Hook for managing persistent toggle state with automatic API synchronization
 * 
 * Features:
 * - Automatically loads state on mount
 * - Automatically saves state on toggle
 * - Handles loading and error states
 * - Can be used for any persistent boolean state
 * 
 * @example
 * ```tsx
 * const { enabled, toggle, loading } = usePersistentToggle({
 *   resourceId: 'openai',
 *   getEndpoint: '/v1/system/settings/integrations/{id}/',
 *   saveEndpoint: '/v1/system/settings/integrations/{id}/save/',
 *   onToggleSuccess: (enabled) => toast.success(`Integration ${enabled ? 'enabled' : 'disabled'}`),
 * });
 * ```
 */
export function usePersistentToggle(
  options: UsePersistentToggleOptions
): UsePersistentToggleReturn {
  const {
    resourceId,
    getEndpoint,
    saveEndpoint,
    initialEnabled = false,
    extractEnabled = (data: any) => data?.enabled ?? false,
    buildPayload = (currentData: any, enabled: boolean) => ({ ...currentData, enabled }),
    onToggleSuccess,
    onToggleError,
    loadOnMount = true,
  } = options;

  const [enabled, setEnabled] = useState(initialEnabled);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const [data, setData] = useState<any>(null);

  /**
   * Load state from API
   */
  const loadState = useCallback(async () => {
    setLoading(true);
    setError(null);
    
    try {
      const endpoint = getEndpoint.replace('{id}', resourceId);
      const result = await fetchAPI(endpoint);
      
      if (result.success && result.data) {
        const apiData = result.data;
        setData(apiData);
        const newEnabled = extractEnabled(apiData);
        setEnabled(newEnabled);
      } else {
        // No data yet - use initial state
        setData({});
        setEnabled(initialEnabled);
      }
    } catch (err: any) {
      const error = err instanceof Error ? err : new Error(String(err));
      setError(error);
      console.error(`Error loading state for ${resourceId}:`, error);
      // Don't throw - just log and keep initial state
    } finally {
      setLoading(false);
    }
  }, [resourceId, getEndpoint, extractEnabled, initialEnabled]);

  /**
   * Save state to API
   */
  const saveState = useCallback(async (newEnabled: boolean) => {
    setLoading(true);
    setError(null);
    
    try {
      const endpoint = saveEndpoint.replace('{id}', resourceId);
      const payload = buildPayload(data || {}, newEnabled);
      
      const result = await fetchAPI(endpoint, {
        method: 'POST',
        body: JSON.stringify(payload),
      });
      
      if (result.success) {
        // Update local state
        const updatedData = { ...(data || {}), enabled: newEnabled };
        setData(updatedData);
        setEnabled(newEnabled);
        
        // Call success callback - pass both enabled state and full config data
        if (onToggleSuccess) {
          onToggleSuccess(newEnabled, updatedData);
        }
      } else {
        throw new Error(result.error || 'Failed to save state');
      }
    } catch (err: any) {
      const error = err instanceof Error ? err : new Error(String(err));
      setError(error);
      console.error(`Error saving state for ${resourceId}:`, error);
      
      // Call error callback
      if (onToggleError) {
        onToggleError(error);
      }
      
      // Revert to previous state on error
      // Don't throw - let component handle error display
    } finally {
      setLoading(false);
    }
  }, [resourceId, saveEndpoint, buildPayload, data, onToggleSuccess, onToggleError]);

  /**
   * Toggle function - automatically persists
   */
  const toggle = useCallback(async (newEnabled: boolean) => {
    await saveState(newEnabled);
  }, [saveState]);

  /**
   * Refresh state from API
   */
  const refresh = useCallback(async () => {
    await loadState();
  }, [loadState]);

  // Load state on mount - only once, don't re-run when dependencies change
  useEffect(() => {
    if (loadOnMount) {
      loadState();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [loadOnMount]); // Only depend on loadOnMount, not loadState

  return {
    enabled,
    toggle,
    loading,
    error,
    data,
    refresh,
  };
}

