"use client"

import React, { createContext, useContext, useState, useCallback, useEffect } from "react"
import { WizardContextValue, WizardStep, FormWizardProps } from "./types"

const FormWizardContext = createContext<WizardContextValue | null>(null)

export const useFormWizard = () => {
  const context = useContext(FormWizardContext)
  if (!context) {
    throw new Error("useFormWizard must be used within a FormWizardProvider")
  }
  return context
}

interface FormWizardProviderProps {
  children: React.ReactNode
  steps: WizardStep[]
  initialStep?: number
  onStepChange?: FormWizardProps['onStepChange']
  onComplete?: FormWizardProps['onComplete']
  validateOnStepChange?: boolean
  allowBackNavigation?: boolean
  allowStepSkip?: boolean
  autoSave?: boolean
  autoSaveDelay?: number
  onAutoSave?: FormWizardProps['onAutoSave']
  persistData?: boolean
  storageKey?: string
}

export const FormWizardProvider: React.FC<FormWizardProviderProps> = ({
  children,
  steps,
  initialStep = 0,
  onStepChange,
  onComplete,
  validateOnStepChange = true,
  allowBackNavigation = true,
  allowStepSkip = false,
  autoSave = false,
  autoSaveDelay = 2000,
  onAutoSave,
  persistData = false,
  storageKey = "form-wizard-data"
}) => {
  const [currentStep, setCurrentStep] = useState(initialStep)
  const [stepData, setStepData] = useState<Record<string, any>>({})
  const [completedSteps, setCompletedSteps] = useState<Set<number>>(new Set())
  const [isLoading, setIsLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  // Load persisted data on mount
  useEffect(() => {
    if (persistData && typeof window !== 'undefined') {
      const savedData = localStorage.getItem(storageKey)
      if (savedData) {
        try {
          const parsed = JSON.parse(savedData)
          setStepData(parsed.stepData || {})
          setCurrentStep(parsed.currentStep || 0)
          setCompletedSteps(new Set(parsed.completedSteps || []))
        } catch (e) {
          console.error("Failed to load persisted wizard data:", e)
        }
      }
    }
  }, [persistData, storageKey])

  // Auto-save functionality
  useEffect(() => {
    if (!autoSave || !onAutoSave) return

    const timeoutId = setTimeout(() => {
      const currentStepData = stepData[steps[currentStep].id]
      if (currentStepData) {
        onAutoSave(steps[currentStep].id, currentStepData)
      }
    }, autoSaveDelay)

    return () => clearTimeout(timeoutId)
  }, [stepData, currentStep, autoSave, autoSaveDelay, onAutoSave, steps])

  // Persist data when it changes
  useEffect(() => {
    if (persistData && typeof window !== 'undefined') {
      const dataToSave = {
        stepData,
        currentStep,
        completedSteps: Array.from(completedSteps)
      }
      localStorage.setItem(storageKey, JSON.stringify(dataToSave))
    }
  }, [stepData, currentStep, completedSteps, persistData, storageKey])

  const validateCurrentStep = useCallback(async (): Promise<boolean> => {
    const step = steps[currentStep]
    
    // First check HTML5 validation for required fields
    if (typeof window !== 'undefined') {
      const stepElement = document.querySelector('[data-wizard-step-content]')
      if (stepElement) {
        const requiredInputs = stepElement.querySelectorAll('input[required], select[required], textarea[required]')
        const emptyFields: string[] = []
        
        requiredInputs.forEach((input: Element) => {
          const htmlInput = input as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
          if (!htmlInput.value || htmlInput.value.trim() === '') {
            const label = document.querySelector(`label[for="${htmlInput.id}"]`)
            const fieldName = label ? (label.textContent?.replace(' *', '') || 'Field') : htmlInput.name || htmlInput.id || 'Field'
            emptyFields.push(fieldName)
          }
        })
        
        // Check for required checkboxes
        const requiredCheckboxes = stepElement.querySelectorAll('input[type="checkbox"][required]')
        requiredCheckboxes.forEach((checkbox: Element) => {
          const htmlCheckbox = checkbox as HTMLInputElement
          if (!htmlCheckbox.checked) {
            const label = document.querySelector(`label[for="${htmlCheckbox.id}"]`)
            const fieldName = label ? (label.textContent?.replace(' *', '') || 'Checkbox') : htmlCheckbox.name || htmlCheckbox.id || 'Checkbox'
            emptyFields.push(fieldName)
          }
        })
        
        if (emptyFields.length > 0) {
          setError(`Please fill in the following required fields: ${emptyFields.join(', ')}`)
          return false
        }
      }
    }
    
    // Then run custom validation if provided
    if (!step.validation) return true

    setIsLoading(true)
    setError(null)

    try {
      const result = await step.validation()
      
      // Handle boolean return
      if (typeof result === 'boolean') {
        if (!result) {
          setError("Please complete all required fields before proceeding")
        }
        return result
      }
      
      // Handle object return {isValid: boolean, error?: string, errors?: string[]}
      if (typeof result === 'object' && result !== null && 'isValid' in result) {
        const validationResult = result as { isValid: boolean; error?: string; errors?: string[] }
        if (!validationResult.isValid) {
          if (validationResult.error) {
            setError(validationResult.error)
          } else if (validationResult.errors && Array.isArray(validationResult.errors)) {
            setError(validationResult.errors.join(', '))
          } else {
            setError("Please complete all required fields before proceeding")
          }
        }
        return validationResult.isValid
      }
      
      // Invalid return type
      setError("Invalid validation response")
      return false
    } catch (err) {
      setError(err instanceof Error ? err.message : "Validation failed")
      return false
    } finally {
      setIsLoading(false)
    }
  }, [currentStep, steps])

  const updateStepData = useCallback((stepId: string, data: any) => {
    setStepData(prev => ({
      ...prev,
      [stepId]: { ...prev[stepId], ...data }
    }))
    setError(null)
  }, [])

  const goToStep = useCallback(async (stepIndex: number) => {
    if (stepIndex < 0 || stepIndex >= steps.length) return
    if (stepIndex === currentStep) return

    const targetStep = steps[stepIndex]
    const isDisabled = typeof targetStep.isDisabled === 'function' 
      ? targetStep.isDisabled(currentStep, steps)
      : targetStep.isDisabled

    if (isDisabled) return

    // Validate current step if moving forward
    if (validateOnStepChange && stepIndex > currentStep) {
      const isValid = await validateCurrentStep()
      if (!isValid) return
    }

    // Call exit handler for current step
    const currentStepObj = steps[currentStep]
    if (currentStepObj.onExit) {
      await currentStepObj.onExit()
    }

    // Update completed steps
    if (stepIndex > currentStep) {
      setCompletedSteps(prev => new Set([...prev, currentStep]))
    }

    // Call enter handler for new step
    if (targetStep.onEnter) {
      await targetStep.onEnter()
    }

    const previousStep = currentStep
    setCurrentStep(stepIndex)
    onStepChange?.(stepIndex, previousStep)
  }, [currentStep, steps, validateOnStepChange, validateCurrentStep, onStepChange])

  const goToNext = useCallback(() => {
    goToStep(currentStep + 1)
  }, [currentStep, goToStep])

  const goToPrevious = useCallback(() => {
    if (!allowBackNavigation) return
    goToStep(currentStep - 1)
  }, [currentStep, goToStep, allowBackNavigation])

  const completeWizard = useCallback(async () => {
    const isValid = await validateCurrentStep()
    if (!isValid) return

    setCompletedSteps(prev => new Set([...prev, currentStep]))
    
    if (onComplete) {
      setIsLoading(true)
      try {
        await onComplete(stepData)
        
        // Clear persisted data after successful completion
        if (persistData && typeof window !== 'undefined') {
          localStorage.removeItem(storageKey)
        }
      } catch (err) {
        setError(err instanceof Error ? err.message : "Failed to complete wizard")
      } finally {
        setIsLoading(false)
      }
    }
  }, [currentStep, stepData, validateCurrentStep, onComplete, persistData, storageKey])

  const resetWizard = useCallback(() => {
    setCurrentStep(0)
    setStepData({})
    setCompletedSteps(new Set())
    setError(null)
    
    if (persistData && typeof window !== 'undefined') {
      localStorage.removeItem(storageKey)
    }
  }, [persistData, storageKey])

  const isStepCompleted = useCallback((stepIndex: number) => {
    return completedSteps.has(stepIndex)
  }, [completedSteps])

  const isStepAccessible = useCallback((stepIndex: number) => {
    if (stepIndex === 0) return true
    if (allowStepSkip) return true
    
    // Check if all previous steps are completed
    for (let i = 0; i < stepIndex; i++) {
      if (!completedSteps.has(i) && !steps[i].isOptional) {
        return false
      }
    }
    
    return true
  }, [completedSteps, allowStepSkip, steps])

  const value: WizardContextValue = {
    steps,
    currentStep,
    stepData,
    isLoading,
    error,
    goToNext,
    goToPrevious,
    goToStep,
    updateStepData: (data: any) => updateStepData(steps[currentStep].id, data),
    validateCurrentStep,
    completeWizard,
    resetWizard,
    isStepCompleted,
    isStepAccessible,
    canGoNext: currentStep < steps.length - 1,
    canGoPrevious: allowBackNavigation && currentStep > 0
  }

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