import React, { createContext, useContext, useState, useEffect, ReactNode, useRef } from 'react';
import type {
  SetupWizardStepConfig,
  StepValidationResult,
  SetupWizardState
} from '../types';

interface SetupWizardContextState {
  currentStepIndex: number;
  steps: SetupWizardStepConfig[];
  stepValidation: Map<string, StepValidationResult>;
  loading: boolean;
  error?: string;
  setupWizardState: SetupWizardState | null;
  refreshTrigger: number;
  scrollContainerRef: React.RefObject<HTMLDivElement>;
}

interface SetupWizardContextActions {
  goToStep: (index: number) => void;
  nextStep: () => void;
  previousStep: () => void;
  validateCurrentStep: () => Promise<StepValidationResult>;
  completeOnboarding: () => Promise<void>;
  dismissOnboarding: () => Promise<void>;
  refreshStepStatus: (stepId: string) => Promise<void>;
  refreshAllSteps: () => Promise<void>;
  triggerRefresh: () => void;
  scrollToTop: () => void;
  setStepWorking: (stepId: string, working: boolean) => void;
}

type SetupWizardContextType = SetupWizardContextState & SetupWizardContextActions;

const SetupWizardContext = createContext<SetupWizardContextType | undefined>(undefined);

export const useSetupWizard = () => {
  const context = useContext(SetupWizardContext);
  if (!context) {
    throw new Error('useSetupWizard must be used within SetupWizardProvider');
  }
  return context;
};

interface SetupWizardProviderProps {
  children: ReactNode;
}

export const SetupWizardProvider: React.FC<SetupWizardProviderProps> = ({ children }) => {
  const [currentStepIndex, setCurrentStepIndex] = useState(0);
  const [steps, setSteps] = useState<SetupWizardStepConfig[]>([]);
  const [stepValidation, setStepValidation] = useState<Map<string, StepValidationResult>>(
    new Map()
  );
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string>();
  const [setupWizardState, setSetupWizardState] = useState<SetupWizardState | null>(null);
  const [refreshTrigger, setRefreshTrigger] = useState(0);
  const scrollContainerRef = useRef<HTMLDivElement>(null);

  // Load steps and initial state
  useEffect(() => {
    const loadInitialData = async () => {
      try {
        console.log('[SetupWizardContext] Preload loaded?:', (window as any).__PRELOAD_LOADED__);
        console.log('[SetupWizardContext] window.setupWizardAPI:', window.setupWizardAPI);
        console.log('[SetupWizardContext] typeof window.setupWizardAPI:', typeof window.setupWizardAPI);
        console.log('[SetupWizardContext] All window keys:', Object.keys(window).filter(k => k.includes('API') || k.includes('PRELOAD')));
        if (window.setupWizardAPI) {
          console.log('[SetupWizardContext] setupWizardAPI keys:', Object.keys(window.setupWizardAPI));
        }

        if (!window.setupWizardAPI) {
          throw new Error('setupWizardAPI is not available on window. Preload script may not have loaded correctly.');
        }

        const [loadedSteps, state] = await Promise.all([
          window.setupWizardAPI.getSteps(),
          window.setupWizardAPI.getState()
        ]);

        setSteps(loadedSteps);
        setSetupWizardState(state);

        // Validate all steps in parallel (non-blocking)
        (async () => {
          const validations = new Map<string, StepValidationResult>();
          const startTime = performance.now();

          // Set all steps to loading initially
          const loadingValidations = new Map<string, StepValidationResult>();
          for (const step of loadedSteps) {
            loadingValidations.set(step.id, {
              isComplete: false,
              canProceed: false,
              isLoading: true
            });
          }
          setStepValidation(loadingValidations);

          console.log(`[Performance] Starting parallel validation of ${loadedSteps.length} steps...`);

          // Validate all steps in parallel using Promise.allSettled
          const validationPromises = loadedSteps.map(async (step) => {
            try {
              const result = await window.setupWizardAPI.validateStep(step.id);
              return { stepId: step.id, result: { ...result, isLoading: false }, error: null };
            } catch (err) {
              console.error(`Failed to validate step ${step.id}:`, err);
              return {
                stepId: step.id,
                result: {
                  isComplete: false,
                  canProceed: false,
                  isLoading: false
                },
                error: err
              };
            }
          });

          // Wait for all validations to complete
          const results = await Promise.allSettled(validationPromises);

          // Process results and update state
          const finalValidations = new Map<string, StepValidationResult>();
          results.forEach((promiseResult) => {
            if (promiseResult.status === 'fulfilled') {
              const { stepId, result } = promiseResult.value;
              finalValidations.set(stepId, result);
            }
          });

          // Update all validations at once for better performance
          setStepValidation(finalValidations);

          const endTime = performance.now();
          const duration = Math.round(endTime - startTime);
          console.log(`[Performance] ✓ Parallel validation completed in ${duration}ms`);
          console.log(`[Performance] Average per step: ${Math.round(duration / loadedSteps.length)}ms`);

          // Find first incomplete step
          const firstIncompleteIndex = loadedSteps.findIndex(step => {
            const validation = finalValidations.get(step.id);
            return !validation?.isComplete;
          });

          if (firstIncompleteIndex !== -1) {
            setCurrentStepIndex(firstIncompleteIndex);
          }
        })();
      } catch (err: any) {
        console.error('Failed to load setupWizard data:', err);
        setError(err.message);
      }
    };

    loadInitialData();
  }, []);

  const goToStep = (index: number) => {
    if (index >= 0 && index < steps.length) {
      setCurrentStepIndex(index);
    }
  };

  const nextStep = () => {
    if (currentStepIndex < steps.length - 1) {
      setCurrentStepIndex(currentStepIndex + 1);
    }
  };

  const previousStep = () => {
    if (currentStepIndex > 0) {
      setCurrentStepIndex(currentStepIndex - 1);
    }
  };

  const validateCurrentStep = async (): Promise<StepValidationResult> => {
    const currentStep = steps[currentStepIndex];
    if (!currentStep) {
      throw new Error('No current step');
    }

    try {
      // Set loading state
      setStepValidation(prev => {
        const current = prev.get(currentStep.id);
        return new Map(prev).set(currentStep.id, {
          ...current,
          isComplete: current?.isComplete ?? false,
          canProceed: current?.canProceed ?? false,
          isLoading: true
        });
      });

      const result = await window.setupWizardAPI.validateStep(currentStep.id);
      setStepValidation(prev => new Map(prev).set(currentStep.id, { ...result, isLoading: false }));

      // Reload fresh state from backend to avoid using stale React state
      const freshState = await window.setupWizardAPI.getState();
      const existingStepData = freshState.stepStatus[currentStep.id];
      const existingData = existingStepData?.data || {};

      const updatedState: SetupWizardState = {
        ...freshState,
        stepStatus: {
          ...freshState.stepStatus,
          [currentStep.id]: {
            completed: result.isComplete,
            lastChecked: Date.now(),
            data: {
              ...existingData,
              ...result.details
            }
          }
        }
      };
      setSetupWizardState(updatedState);
      await window.setupWizardAPI.setState(updatedState);

      return result;
    } catch (err: any) {
      console.error('Failed to validate step:', err);
      // Clear loading state on error
      setStepValidation(prev => {
        const current = prev.get(currentStep.id);
        return new Map(prev).set(currentStep.id, {
          ...current,
          isComplete: current?.isComplete ?? false,
          canProceed: current?.canProceed ?? false,
          isLoading: false
        });
      });
      throw err;
    }
  };

  const refreshStepStatus = async (stepId: string): Promise<void> => {
    try {
      // Set loading state
      setStepValidation(prev => {
        const current = prev.get(stepId);
        return new Map(prev).set(stepId, {
          ...current,
          isComplete: current?.isComplete ?? false,
          canProceed: current?.canProceed ?? false,
          isLoading: true
        });
      });

      const result = await window.setupWizardAPI.validateStep(stepId);
      setStepValidation(prev => new Map(prev).set(stepId, { ...result, isLoading: false }));

      // Reload fresh state from backend to avoid using stale React state
      const freshState = await window.setupWizardAPI.getState();
      const existingStepData = freshState.stepStatus[stepId];
      const existingData = existingStepData?.data || {};

      const updatedState: SetupWizardState = {
        ...freshState,
        stepStatus: {
          ...freshState.stepStatus,
          [stepId]: {
            completed: result.isComplete,
            lastChecked: Date.now(),
            data: {
              ...existingData,
              ...result.details
            }
          }
        }
      };
      setSetupWizardState(updatedState);
      await window.setupWizardAPI.setState(updatedState);

      // Note: Tray icon is updated when window gains focus or wizard completes
      // We don't update it here to avoid validating all steps on every refresh
    } catch (err: any) {
      console.error('Failed to refresh step status:', err);
      // Clear loading state on error
      setStepValidation(prev => {
        const current = prev.get(stepId);
        return new Map(prev).set(stepId, {
          ...current,
          isComplete: current?.isComplete ?? false,
          canProceed: current?.canProceed ?? false,
          isLoading: false
        });
      });
      throw err;
    }
  };

  const completeOnboarding = async (): Promise<void> => {
    try {
      // Validate all required steps
      for (const step of steps) {
        if (step.required) {
          const validation = stepValidation.get(step.id);
          if (!validation?.isComplete) {
            throw new Error(`Step "${step.title}" is not complete`);
          }
        }
      }

      // Mark setupWizard as complete
      const updatedState: SetupWizardState = {
        ...setupWizardState!,
        completed: true
      };
      await window.setupWizardAPI.setState(updatedState);
      setSetupWizardState(updatedState);
    } catch (err: any) {
      console.error('Failed to complete setupWizard:', err);
      throw err;
    }
  };

  const dismissOnboarding = async (): Promise<void> => {
    try {
      const updatedState: SetupWizardState = {
        ...setupWizardState!,
        dismissedAt: Date.now()
      };
      await window.setupWizardAPI.setState(updatedState);
      setSetupWizardState(updatedState);
    } catch (err: any) {
      console.error('Failed to dismiss setupWizard:', err);
      throw err;
    }
  };

  const refreshAllSteps = async (): Promise<void> => {
    try {
      const startTime = performance.now();

      // Set all steps to loading
      const loadingValidations = new Map<string, StepValidationResult>();
      for (const step of steps) {
        loadingValidations.set(step.id, {
          isComplete: false,
          canProceed: false,
          isLoading: true
        });
      }
      setStepValidation(loadingValidations);

      console.log(`[Performance] Starting parallel refresh of ${steps.length} steps...`);

      // Validate all steps in parallel
      const validationPromises = steps.map(async (step) => {
        try {
          const result = await window.setupWizardAPI.validateStep(step.id);
          return { stepId: step.id, result: { ...result, isLoading: false }, error: null };
        } catch (err) {
          console.error(`Failed to validate step ${step.id}:`, err);
          return {
            stepId: step.id,
            result: {
              isComplete: false,
              canProceed: false,
              isLoading: false
            },
            error: err
          };
        }
      });

      // Wait for all validations to complete
      const results = await Promise.allSettled(validationPromises);

      // Process results and update state
      const finalValidations = new Map<string, StepValidationResult>();
      results.forEach((promiseResult) => {
        if (promiseResult.status === 'fulfilled') {
          const { stepId, result } = promiseResult.value;
          finalValidations.set(stepId, result);
        }
      });

      // Update all validations at once
      setStepValidation(finalValidations);

      const endTime = performance.now();
      const duration = Math.round(endTime - startTime);
      console.log(`[Performance] ✓ Parallel refresh completed in ${duration}ms`);
      console.log(`[Performance] Average per step: ${Math.round(duration / steps.length)}ms`);
    } catch (err: any) {
      console.error('Failed to refresh all steps:', err);
      throw err;
    }
  };

  const triggerRefresh = (): void => {
    setRefreshTrigger(prev => prev + 1);
  };

  const setStepWorking = (stepId: string, working: boolean): void => {
    setStepValidation(prev => {
      const current = prev.get(stepId);
      return new Map(prev).set(stepId, {
        isComplete: current?.isComplete ?? false,
        canProceed: current?.canProceed ?? false,
        ...current,
        isLoading: working
      });
    });
  };

  const scrollToTop = (): void => {
    if (scrollContainerRef.current) {
      scrollContainerRef.current.scrollTo({ top: 0, behavior: 'smooth' });
    }
  };

  const value: SetupWizardContextType = {
    currentStepIndex,
    steps,
    stepValidation,
    loading,
    error,
    setupWizardState,
    refreshTrigger,
    scrollContainerRef,
    goToStep,
    nextStep,
    previousStep,
    validateCurrentStep,
    completeOnboarding,
    dismissOnboarding,
    refreshStepStatus,
    refreshAllSteps,
    triggerRefresh,
    scrollToTop,
    setStepWorking
  };

  return (
    <SetupWizardContext.Provider value={value}>
      {children}
    </SetupWizardContext.Provider>
  );
};
