import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import type { WizardStep } from '@/types/quote';

export interface WizardStepDef {
  id: string;
  title: string;
  description: string;
}

/** Map step id from URL hash to step index */
function stepIndexFromHash(steps: WizardStepDef[]): number {
  const hash = window.location.hash.replace('#', '');
  if (!hash) return 0;
  const idx = steps.findIndex((s) => s.id === hash);
  return idx >= 0 ? idx : 0;
}

/** Determine which steps should be marked complete based on a restored index */
function restoredCompletedSteps(upToIndex: number): Set<number> {
  const set = new Set<number>();
  for (let i = 0; i < upToIndex; i++) {
    set.add(i);
  }
  return set;
}

export interface UseWizardReturn {
  currentStep: number;
  steps: WizardStep[];
  totalSteps: number;
  isFirstStep: boolean;
  isLastStep: boolean;
  goToStep: (step: number) => void;
  nextStep: () => void;
  prevStep: () => void;
  markStepComplete: (stepIndex: number) => void;
  markStepIncomplete: (stepIndex: number) => void;
  resetWizard: () => void;
  progress: number;
  canProceed: boolean;
  setCanProceed: (canProceed: boolean) => void;
  currentStepId: string;
  getStepByIndex: (index: number) => WizardStep | undefined;
}

/**
 * Dynamic wizard hook — accepts a step definition array that can change
 * as the user enables/disables services in the discovery step.
 */
export function useWizard(stepDefs: WizardStepDef[]): UseWizardReturn {
  const initialStep = stepIndexFromHash(stepDefs);
  const [currentStep, setCurrentStep] = useState(initialStep);
  const [completedSteps, setCompletedSteps] = useState<Set<number>>(
    () => restoredCompletedSteps(initialStep)
  );
  const [canProceed, setCanProceed] = useState(true);
  const isPopstateRef = useRef(false);
  const prevStepDefsRef = useRef(stepDefs);

  const totalSteps = stepDefs.length;
  const isFirstStep = currentStep === 0;
  const isLastStep = currentStep === totalSteps - 1;

  // When stepDefs change (services toggled), keep current position valid
  useEffect(() => {
    const prevDefs = prevStepDefsRef.current;
    prevStepDefsRef.current = stepDefs;

    if (prevDefs.length === stepDefs.length) return;

    // If current step is beyond new length, clamp it
    if (currentStep >= stepDefs.length) {
      setCurrentStep(Math.max(0, stepDefs.length - 1));
    }

    // If a step was removed, try to stay on the same step id
    const currentId = prevDefs[currentStep]?.id;
    if (currentId) {
      const newIndex = stepDefs.findIndex((s) => s.id === currentId);
      if (newIndex >= 0 && newIndex !== currentStep) {
        setCurrentStep(newIndex);
      }
    }
  }, [stepDefs, currentStep]);

  // Sync URL hash when currentStep changes
  useEffect(() => {
    if (isPopstateRef.current) {
      isPopstateRef.current = false;
      return;
    }
    const stepId = stepDefs[currentStep]?.id;
    if (stepId) {
      const newHash = `#${stepId}`;
      if (window.location.hash !== newHash) {
        window.history.pushState(null, '', newHash);
      }
    }
  }, [currentStep, stepDefs]);

  // Listen for browser back/forward
  useEffect(() => {
    const handlePopState = () => {
      const idx = stepIndexFromHash(stepDefs);
      isPopstateRef.current = true;
      setCurrentStep(idx);
    };

    window.addEventListener('popstate', handlePopState);
    return () => window.removeEventListener('popstate', handlePopState);
  }, [stepDefs]);

  // Set initial hash if none present
  useEffect(() => {
    if (!window.location.hash) {
      const stepId = stepDefs[0]?.id;
      if (stepId) {
        window.history.replaceState(null, '', `#${stepId}`);
      }
    }
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  const steps: WizardStep[] = useMemo(() => {
    return stepDefs.map((step, index) => ({
      ...step,
      isComplete: completedSteps.has(index),
      isActive: index === currentStep,
    }));
  }, [stepDefs, currentStep, completedSteps]);

  const currentStepId = useMemo(() => {
    return stepDefs[currentStep]?.id || '';
  }, [currentStep, stepDefs]);

  const progress = useMemo(() => {
    if (totalSteps <= 1) return 100;
    return Math.round((currentStep / (totalSteps - 1)) * 100);
  }, [currentStep, totalSteps]);

  const goToStep = useCallback(
    (step: number) => {
      if (step >= 0 && step < totalSteps) {
        if (step <= currentStep || completedSteps.has(step - 1) || step === currentStep + 1) {
          setCurrentStep(step);
        }
      }
    },
    [totalSteps, currentStep, completedSteps]
  );

  const nextStep = useCallback(() => {
    if (!isLastStep && canProceed) {
      setCompletedSteps((prev) => new Set(prev).add(currentStep));
      setCurrentStep((prev) => prev + 1);
    }
  }, [currentStep, isLastStep, canProceed]);

  const prevStep = useCallback(() => {
    if (!isFirstStep) {
      setCurrentStep((prev) => prev - 1);
    }
  }, [isFirstStep]);

  const markStepComplete = useCallback((stepIndex: number) => {
    setCompletedSteps((prev) => new Set(prev).add(stepIndex));
  }, []);

  const markStepIncomplete = useCallback((stepIndex: number) => {
    setCompletedSteps((prev) => {
      const newSet = new Set(prev);
      newSet.delete(stepIndex);
      return newSet;
    });
  }, []);

  const resetWizard = useCallback(() => {
    setCurrentStep(0);
    setCompletedSteps(new Set());
    setCanProceed(true);
    window.history.replaceState(null, '', `#${stepDefs[0]?.id}`);
  }, [stepDefs]);

  const getStepByIndex = useCallback(
    (index: number): WizardStep | undefined => {
      return steps[index];
    },
    [steps]
  );

  return {
    currentStep,
    steps,
    totalSteps,
    isFirstStep,
    isLastStep,
    goToStep,
    nextStep,
    prevStep,
    markStepComplete,
    markStepIncomplete,
    resetWizard,
    progress,
    canProceed,
    setCanProceed,
    currentStepId,
    getStepByIndex,
  };
}
