import React, { createContext, useContext, useCallback, useMemo } from 'react';
import { Trigger } from '../types/trigger';
import { Action } from '../types/action';
import { Integration } from '../types/integration';
import { getTriggers, getActions } from '../services/workflows';
import { getIntegrations } from '../services/integrations';
import { useAsyncWithCache, clearAsyncCache } from '../hooks/useAsync';

/**
 * Data context value interface
 */
interface DataContextValue {
  // Triggers
  triggers: Trigger[];
  triggersLoading: boolean;
  triggersError: string | null;
  refetchTriggers: () => Promise<void>;

  // Actions
  actions: Action[];
  actionsLoading: boolean;
  actionsError: string | null;
  refetchActions: () => Promise<void>;

  // Integrations
  integrations: Integration[];
  integrationsLoading: boolean;
  integrationsError: string | null;
  refetchIntegrations: () => Promise<void>;

  // Combined loading state
  isLoading: boolean;

  // Refetch all data
  refetchAll: () => Promise<void>;
}

/**
 * Default context value
 */
const defaultContextValue: DataContextValue = {
  triggers: [],
  triggersLoading: false,
  triggersError: null,
  refetchTriggers: async () => {},

  actions: [],
  actionsLoading: false,
  actionsError: null,
  refetchActions: async () => {},

  integrations: [],
  integrationsLoading: false,
  integrationsError: null,
  refetchIntegrations: async () => {},

  isLoading: false,
  refetchAll: async () => {},
};

/**
 * Data context for sharing API data across components
 */
const DataContext = createContext<DataContextValue>(defaultContextValue);

/**
 * DataProvider component
 *
 * Provides triggers, actions, and integrations data to the component tree.
 * Uses the useAsyncWithCache hook for consistent caching behavior.
 *
 * @example
 * ```tsx
 * function App() {
 *   return (
 *     <DataProvider>
 *       <MyComponent />
 *     </DataProvider>
 *   );
 * }
 *
 * function MyComponent() {
 *   const { triggers, actions, isLoading } = useData();
 *   // Use the data...
 * }
 * ```
 */
export function DataProvider({ children }: { children: React.ReactNode }) {
  // Use cached async hooks for each data type
  const triggersAsync = useAsyncWithCache('triggers', getTriggers, { immediate: true });
  const actionsAsync = useAsyncWithCache('actions', getActions, { immediate: true });
  const integrationsAsync = useAsyncWithCache('integrations', getIntegrations, { immediate: true });

  // Combined loading state
  const isLoading = triggersAsync.loading || actionsAsync.loading || integrationsAsync.loading;

  // Refetch all data
  const refetchAll = useCallback(async () => {
    await Promise.all([
      triggersAsync.execute(),
      actionsAsync.execute(),
      integrationsAsync.execute(),
    ]);
  }, [triggersAsync, actionsAsync, integrationsAsync]);

  // Memoize context value to prevent unnecessary re-renders
  const value = useMemo<DataContextValue>(
    () => ({
      triggers: triggersAsync.data || [],
      triggersLoading: triggersAsync.loading,
      triggersError: triggersAsync.error,
      refetchTriggers: async () => {
        clearAsyncCache('triggers');
        await triggersAsync.execute();
      },

      actions: actionsAsync.data || [],
      actionsLoading: actionsAsync.loading,
      actionsError: actionsAsync.error,
      refetchActions: async () => {
        clearAsyncCache('actions');
        await actionsAsync.execute();
      },

      integrations: integrationsAsync.data || [],
      integrationsLoading: integrationsAsync.loading,
      integrationsError: integrationsAsync.error,
      refetchIntegrations: async () => {
        clearAsyncCache('integrations');
        await integrationsAsync.execute();
      },

      isLoading,
      refetchAll,
    }),
    [
      triggersAsync.data,
      triggersAsync.loading,
      triggersAsync.error,
      triggersAsync.execute,
      actionsAsync.data,
      actionsAsync.loading,
      actionsAsync.error,
      actionsAsync.execute,
      integrationsAsync.data,
      integrationsAsync.loading,
      integrationsAsync.error,
      integrationsAsync.execute,
      isLoading,
      refetchAll,
    ],
  );

  return <DataContext.Provider value={value}>{children}</DataContext.Provider>;
}

/**
 * Hook to access data context
 *
 * @returns Data context value with triggers, actions, integrations and loading states
 * @throws Error if used outside of DataProvider
 *
 * @example
 * ```tsx
 * function TriggerList() {
 *   const { triggers, triggersLoading, triggersError } = useData();
 *
 *   if (triggersLoading) return <Loading />;
 *   if (triggersError) return <Error message={triggersError} />;
 *
 *   return (
 *     <ul>
 *       {triggers.map(t => <li key={t.type}>{t.label}</li>)}
 *     </ul>
 *   );
 * }
 * ```
 */
export function useData(): DataContextValue {
  const context = useContext(DataContext);

  if (context === defaultContextValue) {
    // Check if we're actually inside a provider
    // This is a heuristic - if all values are default, we're probably not in a provider
    console.warn(
      'useData() called outside of DataProvider. ' +
        'Wrap your app with <DataProvider> to access shared data.',
    );
  }

  return context;
}

/**
 * Hook to get only triggers data
 */
export function useTriggers() {
  const { triggers, triggersLoading, triggersError, refetchTriggers } = useData();
  return { triggers, loading: triggersLoading, error: triggersError, refetch: refetchTriggers };
}

/**
 * Hook to get only actions data
 */
export function useActions() {
  const { actions, actionsLoading, actionsError, refetchActions } = useData();
  return { actions, loading: actionsLoading, error: actionsError, refetch: refetchActions };
}

/**
 * Hook to get only integrations data
 */
export function useIntegrations() {
  const { integrations, integrationsLoading, integrationsError, refetchIntegrations } = useData();
  return {
    integrations,
    loading: integrationsLoading,
    error: integrationsError,
    refetch: refetchIntegrations,
  };
}

export default DataContext;
