"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from "react";
import type {
  SpeedPreset,
  VisualizationData,
  VisualizationStep,
} from "@/types/visualization";

const speedValues: Record<SpeedPreset, number> = {
  slow: 2000,
  normal: 1000,
  fast: 500,
};

interface VisualizationContextValue {
  // Data
  data: VisualizationData | null;
  currentStep: VisualizationStep | null;
  stepIndex: number;
  totalSteps: number;

  // Playback state
  isPlaying: boolean;
  speed: SpeedPreset;

  // Navigation actions
  goToStep: (index: number) => void;
  nextStep: () => void;
  prevStep: () => void;
  play: () => void;
  pause: () => void;
  togglePlayback: () => void;
  setSpeed: (speed: SpeedPreset) => void;

  // State queries
  canGoNext: boolean;
  canGoPrev: boolean;
}

const VisualizationContext = createContext<VisualizationContextValue | null>(
  null
);

interface VisualizationProviderProps {
  data: VisualizationData;
  initialStep?: number;
  autoPlay?: boolean;
  children: ReactNode;
}

export function VisualizationProvider({
  data,
  initialStep = 0,
  autoPlay = false,
  children,
}: VisualizationProviderProps) {
  const [stepIndex, setStepIndex] = useState(initialStep);
  const [isPlaying, setIsPlaying] = useState(autoPlay);
  const [speed, setSpeed] = useState<SpeedPreset>("normal");
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);

  const totalSteps = data.steps.length;
  const currentStep = data.steps[stepIndex] ?? null;
  const canGoNext = stepIndex < totalSteps - 1;
  const canGoPrev = stepIndex > 0;

  const goToStep = useCallback(
    (index: number) => {
      const clampedIndex = Math.max(0, Math.min(index, totalSteps - 1));
      setStepIndex(clampedIndex);
    },
    [totalSteps]
  );

  const nextStep = useCallback(() => {
    if (canGoNext) {
      setStepIndex((prev) => prev + 1);
    } else {
      setIsPlaying(false);
    }
  }, [canGoNext]);

  const prevStep = useCallback(() => {
    if (canGoPrev) {
      setStepIndex((prev) => prev - 1);
    }
  }, [canGoPrev]);

  const play = useCallback(() => {
    if (stepIndex >= totalSteps - 1) {
      setStepIndex(0);
    }
    setIsPlaying(true);
  }, [stepIndex, totalSteps]);

  const pause = useCallback(() => {
    setIsPlaying(false);
  }, []);

  const togglePlayback = useCallback(() => {
    if (isPlaying) {
      pause();
    } else {
      play();
    }
  }, [isPlaying, play, pause]);

  // Auto-advance when playing
  useEffect(() => {
    if (isPlaying) {
      intervalRef.current = setInterval(() => {
        setStepIndex((prev) => {
          if (prev >= totalSteps - 1) {
            setIsPlaying(false);
            return prev;
          }
          return prev + 1;
        });
      }, speedValues[speed]);
    }

    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
    };
  }, [isPlaying, speed, totalSteps]);

  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      // Don't capture if user is typing in an input
      if (
        event.target instanceof HTMLInputElement ||
        event.target instanceof HTMLTextAreaElement
      ) {
        return;
      }

      switch (event.key) {
        case "ArrowLeft":
          event.preventDefault();
          prevStep();
          break;
        case "ArrowRight":
          event.preventDefault();
          nextStep();
          break;
        case " ":
          event.preventDefault();
          togglePlayback();
          break;
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [prevStep, nextStep, togglePlayback]);

  const value = useMemo<VisualizationContextValue>(
    () => ({
      data,
      currentStep,
      stepIndex,
      totalSteps,
      isPlaying,
      speed,
      goToStep,
      nextStep,
      prevStep,
      play,
      pause,
      togglePlayback,
      setSpeed,
      canGoNext,
      canGoPrev,
    }),
    [
      data,
      currentStep,
      stepIndex,
      totalSteps,
      isPlaying,
      speed,
      goToStep,
      nextStep,
      prevStep,
      play,
      pause,
      togglePlayback,
      canGoNext,
      canGoPrev,
    ]
  );

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

export function useVisualization(): VisualizationContextValue {
  const context = useContext(VisualizationContext);
  if (!context) {
    throw new Error(
      "useVisualization must be used within a VisualizationProvider"
    );
  }
  return context;
}
