'use client';

import { useCallback, useEffect, useRef, useState } from 'react';
import type {
  AlgorithmDefinition,
  PlaybackSpeed,
  PlaybackState,
  UseVisualizationReturn,
  VisualizationControls,
} from './types';

const SPEED_MULTIPLIERS: Record<PlaybackSpeed, number> = {
  0.5: 2,
  1: 1,
  2: 0.5,
};

const BASE_STEP_DURATION = 1500;

export function useVisualization(
  algorithm: AlgorithmDefinition
): UseVisualizationReturn {
  const [playback, setPlayback] = useState<PlaybackState>({
    isPlaying: false,
    currentStepIndex: 0,
    speed: 1,
  });

  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const totalSteps = algorithm.steps.length;

  const clearAutoAdvance = useCallback(() => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
  }, []);

  const stepForward = useCallback(() => {
    setPlayback((prev) => ({
      ...prev,
      currentStepIndex: Math.min(prev.currentStepIndex + 1, totalSteps - 1),
    }));
  }, [totalSteps]);

  const stepBackward = useCallback(() => {
    setPlayback((prev) => ({
      ...prev,
      currentStepIndex: Math.max(prev.currentStepIndex - 1, 0),
    }));
  }, []);

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

  const goToFirst = useCallback(() => {
    setPlayback((prev) => ({
      ...prev,
      currentStepIndex: 0,
    }));
  }, []);

  const goToLast = useCallback(() => {
    setPlayback((prev) => ({
      ...prev,
      currentStepIndex: totalSteps - 1,
    }));
  }, [totalSteps]);

  const pause = useCallback(() => {
    clearAutoAdvance();
    setPlayback((prev) => ({
      ...prev,
      isPlaying: false,
    }));
  }, [clearAutoAdvance]);

  const play = useCallback(() => {
    setPlayback((prev) => {
      if (prev.currentStepIndex >= totalSteps - 1) {
        return { ...prev, isPlaying: true, currentStepIndex: 0 };
      }
      return { ...prev, isPlaying: true };
    });
  }, [totalSteps]);

  const togglePlay = useCallback(() => {
    setPlayback((prev) => {
      if (prev.isPlaying) {
        clearAutoAdvance();
        return { ...prev, isPlaying: false };
      }
      if (prev.currentStepIndex >= totalSteps - 1) {
        return { ...prev, isPlaying: true, currentStepIndex: 0 };
      }
      return { ...prev, isPlaying: true };
    });
  }, [clearAutoAdvance, totalSteps]);

  const setSpeed = useCallback((speed: PlaybackSpeed) => {
    setPlayback((prev) => ({
      ...prev,
      speed,
    }));
  }, []);

  useEffect(() => {
    if (playback.isPlaying) {
      const interval =
        BASE_STEP_DURATION * SPEED_MULTIPLIERS[playback.speed];

      intervalRef.current = setInterval(() => {
        setPlayback((prev) => {
          if (prev.currentStepIndex >= totalSteps - 1) {
            clearAutoAdvance();
            return { ...prev, isPlaying: false };
          }
          return { ...prev, currentStepIndex: prev.currentStepIndex + 1 };
        });
      }, interval);
    } else {
      clearAutoAdvance();
    }

    return clearAutoAdvance;
  }, [playback.isPlaying, playback.speed, totalSteps, clearAutoAdvance]);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (
        e.target instanceof HTMLInputElement ||
        e.target instanceof HTMLTextAreaElement
      ) {
        return;
      }

      switch (e.key) {
        case ' ':
          e.preventDefault();
          togglePlay();
          break;
        case 'ArrowLeft':
          e.preventDefault();
          stepBackward();
          break;
        case 'ArrowRight':
          e.preventDefault();
          stepForward();
          break;
        case 'Home':
          e.preventDefault();
          goToFirst();
          break;
        case 'End':
          e.preventDefault();
          goToLast();
          break;
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [togglePlay, stepBackward, stepForward, goToFirst, goToLast]);

  const currentStep = algorithm.steps[playback.currentStepIndex];
  const progress =
    totalSteps > 1
      ? (playback.currentStepIndex / (totalSteps - 1)) * 100
      : 100;

  const controls: VisualizationControls = {
    play,
    pause,
    togglePlay,
    stepForward,
    stepBackward,
    goToStep,
    goToFirst,
    goToLast,
    setSpeed,
  };

  return {
    currentStep,
    currentStepIndex: playback.currentStepIndex,
    totalSteps,
    playback,
    controls,
    currentPhase: currentStep.phase,
    progress,
  };
}
