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

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

interface LearnerHubContextActions {
  goToStep: (index: number) => void;
  nextStep: () => void;
  previousStep: () => void;
  validateCurrentStep: () => Promise<StepValidationResult>;
  completeWizard: () => Promise<void>;
  dismissWizard: () => Promise<void>;
  refreshStepStatus: (stepId: string) => Promise<void>;
  refreshAllSteps: () => Promise<void>;
  triggerRefresh: () => void;
  scrollToTop: () => void;
}

type LearnerHubContextType = LearnerHubContextState & LearnerHubContextActions;

const LearnerHubContext = createContext<LearnerHubContextType | undefined>(undefined);

export const useLearnerHub = () => {
  const context = useContext(LearnerHubContext);
  if (!context) {
    throw new Error('useLearnerHub must be used within LearnerHubProvider');
  }
  return context;
};

interface LearnerHubProviderProps {
  children: ReactNode;
}

export const LearnerHubProvider: React.FC<LearnerHubProviderProps> = ({ 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 [learnerHubState, setLearnerHubState] = useState<LearnerHubSetupState | null>(null);
  const [refreshTrigger, setRefreshTrigger] = useState(0);
  const scrollContainerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const loadInitialData = async () => {
      try {
        if (!window.learnerHubAPI) {
          throw new Error('learnerHubAPI is not available on window');
        }

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

        setSteps(loadedSteps);
        setLearnerHubState(state);

        (async () => {
          const loadingValidations = new Map<string, StepValidationResult>();
          for (const step of loadedSteps) {
            loadingValidations.set(step.id, { isComplete: false, canProceed: false, isLoading: true });
          }
          setStepValidation(loadingValidations);

          const validationPromises = loadedSteps.map(async (step) => {
            try {
              const result = await window.learnerHubAPI.validateStep(step.id);
              return { stepId: step.id, result: { ...result, isLoading: false }, error: null };
            } catch (err) {
              return { stepId: step.id, result: { isComplete: false, canProceed: false, isLoading: false }, error: err };
            }
          });

          const results = await Promise.allSettled(validationPromises);
          const finalValidations = new Map<string, StepValidationResult>();
          results.forEach((promiseResult) => {
            if (promiseResult.status === 'fulfilled') {
              const { stepId, result } = promiseResult.value;
              finalValidations.set(stepId, result);
            }
          });
          setStepValidation(finalValidations);

          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 learner hub 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 {
      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.learnerHubAPI.validateStep(currentStep.id);
      setStepValidation(prev => new Map(prev).set(currentStep.id, { ...result, isLoading: false }));

      const freshState = await window.learnerHubAPI.getState();
      const existingData = freshState.stepStatus[currentStep.id]?.data || {};
      const updatedState: LearnerHubSetupState = {
        ...freshState,
        stepStatus: {
          ...freshState.stepStatus,
          [currentStep.id]: {
            completed: result.isComplete,
            lastChecked: Date.now(),
            data: { ...existingData, ...result.details }
          }
        }
      };
      setLearnerHubState(updatedState);
      await window.learnerHubAPI.setState(updatedState);

      return result;
    } catch (err: any) {
      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 {
      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.learnerHubAPI.validateStep(stepId);
      setStepValidation(prev => new Map(prev).set(stepId, { ...result, isLoading: false }));

      const freshState = await window.learnerHubAPI.getState();
      const existingData = freshState.stepStatus[stepId]?.data || {};
      const updatedState: LearnerHubSetupState = {
        ...freshState,
        stepStatus: {
          ...freshState.stepStatus,
          [stepId]: {
            completed: result.isComplete,
            lastChecked: Date.now(),
            data: { ...existingData, ...result.details }
          }
        }
      };
      setLearnerHubState(updatedState);
      await window.learnerHubAPI.setState(updatedState);
    } catch (err: any) {
      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 completeWizard = async (): Promise<void> => {
    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`);
      }
    }
    const updatedState: LearnerHubSetupState = { ...learnerHubState!, completed: true };
    await window.learnerHubAPI.setState(updatedState);
    setLearnerHubState(updatedState);
  };

  const dismissWizard = async (): Promise<void> => {
    const updatedState: LearnerHubSetupState = { ...learnerHubState!, dismissedAt: Date.now() };
    await window.learnerHubAPI.setState(updatedState);
    setLearnerHubState(updatedState);
  };

  const refreshAllSteps = async (): Promise<void> => {
    const loadingValidations = new Map<string, StepValidationResult>();
    for (const step of steps) {
      loadingValidations.set(step.id, { isComplete: false, canProceed: false, isLoading: true });
    }
    setStepValidation(loadingValidations);

    const validationPromises = steps.map(async (step) => {
      try {
        const result = await window.learnerHubAPI.validateStep(step.id);
        return { stepId: step.id, result: { ...result, isLoading: false } };
      } catch {
        return { stepId: step.id, result: { isComplete: false, canProceed: false, isLoading: false } };
      }
    });

    const results = await Promise.allSettled(validationPromises);
    const finalValidations = new Map<string, StepValidationResult>();
    results.forEach((promiseResult) => {
      if (promiseResult.status === 'fulfilled') {
        const { stepId, result } = promiseResult.value;
        finalValidations.set(stepId, result);
      }
    });
    setStepValidation(finalValidations);
  };

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

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

  const value: LearnerHubContextType = {
    currentStepIndex, steps, stepValidation, loading, error, learnerHubState,
    refreshTrigger, scrollContainerRef,
    goToStep, nextStep, previousStep, validateCurrentStep, completeWizard,
    dismissWizard, refreshStepStatus, refreshAllSteps, triggerRefresh, scrollToTop
  };

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