"use client";

import { useEffect, useRef, useState, useCallback } from "react";

export default function LivePreviewFrame({
  sessionId,
  onScrapeComplete,
  children,
}: {
  sessionId: string;
  children: React.ReactNode;
  onScrapeComplete?: () => void;
}) {
  const imgRef = useRef<HTMLImageElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const wsRef = useRef<WebSocket | null>(null);
  const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const initialPositionSetRef = useRef(false);
  const idleStartTimerRef = useRef<NodeJS.Timeout | null>(null);
  const idleMoveTimerRef = useRef<NodeJS.Timeout | null>(null);
  const [imageLoaded, setImageLoaded] = useState(false);
  const [imageSrc, setImageSrc] = useState<string | null>(null);
  const [isConnecting, setIsConnecting] = useState(true);
  const [cursorPosition, setCursorPosition] = useState<{
    x: number;
    y: number;
  }>({ x: 980, y: 54 });
  const [targetPosition, setTargetPosition] = useState<{
    x: number;
    y: number;
  }>({ x: 980, y: 54 });
  const [isIdle, setIsIdle] = useState(false);

  // Function to start the random idle movement sequence
  const scheduleNextIdleMove = useCallback(() => {
    if (idleMoveTimerRef.current) {
      clearTimeout(idleMoveTimerRef.current);
    }
    const randomDelay = Math.random() * 500 + 500; // 500ms to 1000ms
    idleMoveTimerRef.current = setTimeout(() => {
      if (isIdle) {
        // Check if still idle
        const randomOffsetX = (Math.random() - 0.5) * 10; // -5 to +5 pixels
        const randomOffsetY = (Math.random() - 0.5) * 10;
        // Update target slightly - the main animation loop will handle the movement
        setTargetPosition((prevTarget) => ({
          x: prevTarget.x + randomOffsetX,
          y: prevTarget.y + randomOffsetY,
        }));
        scheduleNextIdleMove(); // Schedule the next one
      }
    }, randomDelay);
  }, [isIdle]);

  // Effect to handle starting/stopping idle movement sequence
  useEffect(() => {
    if (isIdle) {
      scheduleNextIdleMove();
    } else {
      if (idleMoveTimerRef.current) {
        clearTimeout(idleMoveTimerRef.current);
      }
    }
    // Cleanup function for this effect
    return () => {
      if (idleMoveTimerRef.current) {
        clearTimeout(idleMoveTimerRef.current);
      }
    };
  }, [isIdle, scheduleNextIdleMove]);

  // Main Animation effect (runs continuously)
  useEffect(() => {
    let animationFrameId: number | null = null;
    const step = () => {
      setCursorPosition((currentPos) => {
        const dx = targetPosition.x - currentPos.x;
        const dy = targetPosition.y - currentPos.y;
        const isClose = Math.abs(dx) < 0.1 && Math.abs(dy) < 0.1;

        if (isClose) {
          // Reached target
          if (!isIdle && !idleStartTimerRef.current) {
            // Only start the idle timer if not already idle and no timer is running
            idleStartTimerRef.current = setTimeout(() => {
              setIsIdle(true);
              idleStartTimerRef.current = null; // Clear ref after timer runs
            }, 5000);
          }
          if (animationFrameId) {
            cancelAnimationFrame(animationFrameId);
            animationFrameId = null;
          }
          return targetPosition; // Snap to final position
        } else {
          // Moving towards target
          // If we were waiting to go idle, cancel it because we're moving again
          if (idleStartTimerRef.current) {
            clearTimeout(idleStartTimerRef.current);
            idleStartTimerRef.current = null;
          }
          // Ensure idle state is false if we are moving significantly
          if (isIdle) setIsIdle(false);

          const nextX = currentPos.x + dx * 0.05; // Keep slow easing for now
          const nextY = currentPos.y + dy * 0.05;
          animationFrameId = requestAnimationFrame(step);
          return { x: nextX, y: nextY };
        }
      });
    };

    // Start animation frame loop
    animationFrameId = requestAnimationFrame(step);

    // Cleanup function for main animation loop
    return () => {
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
      }
      // Also clear idle start timer on unmount or if target changes causing effect re-run
      if (idleStartTimerRef.current) {
        clearTimeout(idleStartTimerRef.current);
      }
    };
  }, [targetPosition, isIdle]); // Re-run main loop logic if targetPosition changes

  const cleanupConnection = () => {
    if (reconnectTimeoutRef.current) {
      clearTimeout(reconnectTimeoutRef.current);
      reconnectTimeoutRef.current = null;
    }
    if (wsRef.current) {
      wsRef.current.close();
      wsRef.current = null;
    }
    // Cancel animation frame (handled in effect cleanup, but good practice here too)
    // Clear timers
    if (idleStartTimerRef.current) clearTimeout(idleStartTimerRef.current);
    if (idleMoveTimerRef.current) clearTimeout(idleMoveTimerRef.current);
    // Reset state
    setCursorPosition({ x: 0, y: 0 });
    setTargetPosition({ x: 0, y: 0 });
    setIsIdle(false);
    initialPositionSetRef.current = false;
  };

  useEffect(() => {
    if (onScrapeComplete) {
      cleanupConnection();
    }
  }, [onScrapeComplete]);

  const connect = useCallback(() => {
    setIsConnecting(true);
    // Clear any existing connection
    if (wsRef.current) {
      wsRef.current.close();
      wsRef.current = null;
    }

    // Create new WebSocket connection
    const wsUrl = `wss://api.firecrawl.dev/agent-livecast?userProvidedId=${sessionId}`;

    try {
      const ws = new WebSocket(wsUrl);
      wsRef.current = ws;

      ws.addEventListener("open", () => {
        console.log("Connected - Streaming frames...");
        setIsConnecting(false);
        // Clear any pending reconnection attempts
        if (reconnectTimeoutRef.current) {
          clearTimeout(reconnectTimeoutRef.current);
          reconnectTimeoutRef.current = null;
        }
      });

      ws.addEventListener("message", (event) => {
        try {
          // Try to handle as raw base64 first
          if (
            typeof event.data === "string" &&
            event.data.startsWith("data:image")
          ) {
            setImageSrc(event.data);
            return;
          }

          // If not direct image data, try parsing as JSON
          const data = JSON.parse(event.data);

          if (data.mouseCoordinates) {
            let { x, y } = data.mouseCoordinates;

            // --- Interrupt Idle State ---
            if (idleStartTimerRef.current) {
              clearTimeout(idleStartTimerRef.current);
              idleStartTimerRef.current = null;
            }
            if (isIdle) {
              setIsIdle(false);
              // idleMoveTimerRef is cleared by the isIdle effect cleanup
            }
            // --- End Interrupt Idle State ---

            if (imgRef.current && containerRef.current) {
              const rect = containerRef.current.getBoundingClientRect();
              const imageRect = imgRef.current.getBoundingClientRect();

              // Calculate the scale factor between the original coordinates and our container
              const scaleX = imageRect.width / 1920;
              const scaleY =
                imageRect.height > 2000 ? 0 : imageRect.height / 1080;

              if (x === 0 && y === 0) {
                x = 1800;
                y = 100;
              }

              // Scale the coordinates to match our container size
              const scaledX = x * scaleX;
              const scaledY = y * scaleY;

              setTargetPosition({ x: scaledX, y: scaledY });

              if (!initialPositionSetRef.current) {
                setCursorPosition({ x: scaledX, y: scaledY });
                initialPositionSetRef.current = true;
              }
            }
          }

          if (data.frame) {
            const img = "data:image/jpeg;base64," + data.frame;
            localStorage.setItem("browserImageData", img);
            setImageSrc(img);
          }
        } catch (e) {
          // Try to use raw data as fallback if JSON parsing fails
          if (typeof event.data === "string") {
            setImageSrc(event.data);
          }
        }
      });

      ws.addEventListener("close", (event) => {
        console.log(`Disconnected (Code: ${event.code})`);
        wsRef.current = null;

        // Attempt to reconnect after a delay for any unexpected closure
        if (event.code !== 1000) {
          reconnectTimeoutRef.current = setTimeout(() => {
            if (sessionId) {
              connect();
            }
          }, 3000); // Wait 3 seconds before reconnecting
        }
      });

      ws.addEventListener("error", (error) => {
        console.error("Connection error - Will attempt to reconnect");
      });
    } catch (error) {
      console.error("Failed to create connection");
      setIsConnecting(false);
    }
  }, [sessionId, isIdle]);

  useEffect(() => {
    // Only connect if we have a sessionId
    if (sessionId) {
      connect();

      return () => {
        cleanupConnection();
      };
    } else {
      // Clean up any existing connection
      cleanupConnection();
      console.log("Waiting for session ID...");

      return () => {
        cleanupConnection();
      };
    }
  }, [sessionId, connect]); // Re-run effect when sessionId changes

  return (
    <div
      ref={containerRef}
      className="relative w-full h-full flex items-center justify-center"
    >
      {/* Cursor */}
      {cursorPosition && cursorPosition.x !== 0 && cursorPosition.y !== 0 && (
        <div
          className="absolute pointer-events-none transform-gpu"
          style={{
            left: `${cursorPosition.x}px`,
            top: `${cursorPosition.y}px`,
            width: "50px",
            height: "50px",
            backgroundImage: `url("/images/agent-cursor.svg")`,
            backgroundSize: "contain",
            backgroundRepeat: "no-repeat",
            transform: "translate(-20%, -20%)",
            zIndex: 10,
            transition: isIdle ? "all 0.5s ease-out" : "all 0.1s linear",
          }}
        />
      )}

      {/* Children fallback */}
      {children && !imgRef.current?.src ? (
        <div className="h-full w-full flex items-center justify-center">
          {children}
        </div>
      ) : null}

      {/* Preview image - Using regular img tag for dynamic WebSocket stream */}
      {imageSrc && (
        <img
          ref={imgRef}
          id="live-frame"
          src={imageSrc}
          alt="Live preview"
          onLoad={() => {
            setImageLoaded(true);
            if (onScrapeComplete) onScrapeComplete();
          }}
          className={`w-auto h-auto max-w-full max-h-full object-contain transform-gpu ${
            !imageLoaded ? "opacity-0 scale-95" : "opacity-100 scale-100"
          } transition-all duration-300 ease-out`}
          style={{
            backgroundColor: "#f0f0f0",
          }}
        />
      )}
    </div>
  );
}
