import React, { useEffect, useRef, useState } from 'react';
import { GUIMode, IPoint } from '@fullstackcraftllc/codevideo-types';
import { Box } from '@radix-ui/themes';
import { samplePathPoints } from './coordinateFunctions/mouse-movement/samplePathPoints';
import { generateControlPoints } from './coordinateFunctions/mouse-movement/generateControlPoints';

interface IMouseOverlayProps {
  mode: GUIMode;
  targetMousePosition: IPoint; // Renamed from mousePosition
  mouseVisible: boolean;
  mouseColor?: string;
  previousPosition?: IPoint;
  arcHeight?: number; // Controls the height of the arc (0.3 by default)
  numberOfCurves?: number; // Number of bends to add (1-3, defaults to 1)
  onAnimationFinished?: () => void; // Callback when animation completes
  onCurrentPositionChange?: (position: IPoint) => void; // Callback to report current position
}

export const MouseOverlay = (props: IMouseOverlayProps) => {
  const { 
    mode, 
    mouseVisible, 
    targetMousePosition, // Renamed from mousePosition
    mouseColor,
    arcHeight = 0.3,
    numberOfCurves = 1,
    onAnimationFinished,
    onCurrentPositionChange
  } = props;
  
  const overlayRef = useRef<HTMLDivElement>(null);
  const [currentPosition, setCurrentPosition] = useState<IPoint>(targetMousePosition);
  const [prevPosition, setPrevPosition] = useState<IPoint>(targetMousePosition);
  const [isAnimating, setIsAnimating] = useState<boolean>(false);
  const [pathPoints, setPathPoints] = useState<IPoint[]>([]);
  const animationRef = useRef<number | null>(null);
  
  // Call the position change callback whenever currentPosition changes
  useEffect(() => {
    if (onCurrentPositionChange) {
      onCurrentPositionChange(currentPosition);
    }
  }, [currentPosition, onCurrentPositionChange]);
  
  useEffect(() => {
    // Skip animation if not in replay mode or if this is first render
    if (mode !== 'replay' || (prevPosition.x === targetMousePosition.x && prevPosition.y === targetMousePosition.y)) {
      setCurrentPosition(targetMousePosition);
      setPrevPosition(targetMousePosition);
      return;
    }
    
    // Store previous position before updating
    setPrevPosition(currentPosition);
    
    if (mode === 'replay') {
      // Generate random number of curves (1-3) if not specified
      const curvesToUse = numberOfCurves === 1 ? 
        Math.floor(Math.random() * 3) + 1 : 
        numberOfCurves;
      
      // Generate control points for the path
      const controlPoints = generateControlPoints(
        prevPosition,
        targetMousePosition,
        curvesToUse,
        arcHeight
      );
      
      // Pre-calculate points along the path for smoother animation
      const animationPoints = samplePathPoints(controlPoints, 60); // 60 frames for a smooth animation
      setPathPoints(animationPoints);
      
      setIsAnimating(true);
      
      // Animate along the pre-calculated path
      let startTime: number | null = null;
      const duration = 750; // Match the original transition duration (0.75s)
      
      const animateFrame = (timestamp: number) => {
        if (!startTime) startTime = timestamp;
        const elapsed = timestamp - startTime;
        const progress = Math.min(elapsed / duration, 1);
        
        // Get the point at the current progress
        const frameIndex = Math.min(
          Math.floor(progress * (animationPoints.length - 1)),
          animationPoints.length - 1
        );
        
        const newPosition = animationPoints[frameIndex];
        setCurrentPosition(newPosition);
        
        if (progress < 1) {
          animationRef.current = requestAnimationFrame(animateFrame);
        } else {
          setIsAnimating(false);
          if (onAnimationFinished) {
            onAnimationFinished();
          }
        }
      };
      
      animationRef.current = requestAnimationFrame(animateFrame);
      
      // Cleanup function to cancel animation if component unmounts during animation
      return () => {
        if (animationRef.current !== null) {
          cancelAnimationFrame(animationRef.current);
        }
      };
    } else {
      // In step mode, just jump to the new position
      setCurrentPosition(targetMousePosition);
    }
  }, [targetMousePosition.x, targetMousePosition.y, mode]);

  useEffect(() => {
    if (mode === 'step') {
      setCurrentPosition(targetMousePosition);
      setPrevPosition(targetMousePosition);
    }
  }, [mode, targetMousePosition]);
  
  if (!mouseVisible) {
    return <></>;
  }
  
  return (
    <Box
      id="mouse-overlay"
      ref={overlayRef}
      style={{
        transform: `translate(${currentPosition.x}px, ${currentPosition.y}px) scale(0.8)`,
        transition: isAnimating ? undefined : (mode === 'replay' ? 'transform 0.05s linear' : undefined),
        zIndex: 100000000,
        position: 'absolute',
        pointerEvents: 'none',
        userSelect: 'none',
      }}
    >
      <svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg">
        <path
          d="M 0,0 L 0,20 L 4.5,15.5 L 8.75,23 L 11,22 L 6.75,15 L 13.75,15 Z"
          fill={mouseColor ? mouseColor : 'black'}
          stroke="white"
          strokeWidth="1.5"
          strokeLinejoin="round"
        />
      </svg>
    </Box>
  );
};