"use client";

import { useState, useRef, useEffect } from "react";
import WebcamCapture from "./WebcamCapture";
import PoseLandmarks from "./PoseLandmarks";
import AnimatedSkeleton from "./AnimatedSkeleton";
import ScoreSummary from "./ScoreSummary";

interface Landmark {
  x: number;
  y: number;
  z: number;
  visibility: number;
}

interface MotionMetadata {
  num_frames: number;
  duration: number;
  fps: number;
}

interface DanceGameProps {
  songId: string;
  audioUrl: string;
  onEnd?: () => void;
  onMotionLoaded?: () => void;
  showUploadOnly?: boolean;
}

export default function DanceGame({ 
  songId, 
  audioUrl, 
  onEnd, 
  onMotionLoaded,
  showUploadOnly = false 
}: DanceGameProps) {
  const [motionLoaded, setMotionLoaded] = useState(false);
  const [motionMetadata, setMotionMetadata] = useState<MotionMetadata | null>(
    null
  );
  const [score, setScore] = useState<number | null>(null);
  const [scores, setScores] = useState<number[]>([]);
  const [isPlaying, setIsPlaying] = useState(false);
  const [message, setMessage] = useState<string>("");
  const [referenceLandmarks, setReferenceLandmarks] = useState<
    Landmark[] | null
  >(null);
  const [currentLandmarks, setCurrentLandmarks] = useState<Landmark[] | null>(
    null
  );
  const [showLandmarks, setShowLandmarks] = useState(false);
  const [showSummary, setShowSummary] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);

  const motionFileInputRef = useRef<HTMLInputElement>(null);
  const webcamVideoRef = useRef<HTMLVideoElement>(null);
  const audioRef = useRef<HTMLAudioElement>(null);
  const comparisonIntervalRef = useRef<NodeJS.Timeout | null>(null);
  const animationFrameRef = useRef<number | null>(null);

  const BACKEND_URL =
    process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:8000";

  // Handle motion file upload
  const handleMotionUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    if (!file.name.endsWith(".pkl")) {
      setMessage("Error: Please upload a .pkl file");
      return;
    }

    const formData = new FormData();
    formData.append("file", file);

    try {
      const response = await fetch(`${BACKEND_URL}/api/load-motion`, {
        method: "POST",
        body: formData,
      });

      if (response.ok) {
        const data = await response.json();
        setMotionMetadata(data.metadata);
        setMotionLoaded(true);
        setMessage(
          `Motion loaded! ${
            data.metadata.num_frames
          } frames, ${data.metadata.duration.toFixed(1)}s duration`
        );
        // Call the callback to notify parent component
        if (onMotionLoaded) {
          onMotionLoaded();
        }
      } else {
        const error = await response.json();
        setMessage(`Error: ${error.detail}`);
      }
    } catch (error) {
      setMessage(
        "Error connecting to backend. Make sure it's running on port 8000."
      );
      console.error("Error uploading motion:", error);
    }
  };

  // Update reference skeleton based on audio time
  const updateReferenceSkeleton = async () => {
    if (!audioRef.current || !motionLoaded) return;

    const timestamp = audioRef.current.currentTime;
    setCurrentTime(timestamp);

    try {
      const response = await fetch(
        `${BACKEND_URL}/api/get-reference-frame?timestamp=${timestamp}`
      );

      if (response.ok) {
        const data = await response.json();
        setReferenceLandmarks(data.landmarks);
      }
    } catch (error) {
      console.error("Error fetching reference frame:", error);
    }

    // Continue animation loop
    if (isPlaying) {
      animationFrameRef.current = requestAnimationFrame(
        updateReferenceSkeleton
      );
    }
  };

  // Start/stop animation loop
  useEffect(() => {
    if (isPlaying && motionLoaded) {
      animationFrameRef.current = requestAnimationFrame(
        updateReferenceSkeleton
      );
    } else {
      if (animationFrameRef.current) {
        cancelAnimationFrame(animationFrameRef.current);
      }
    }

    return () => {
      if (animationFrameRef.current) {
        cancelAnimationFrame(animationFrameRef.current);
      }
    };
  }, [isPlaying, motionLoaded]);

  // Handle audio playback and comparison
  useEffect(() => {
    if (!audioRef.current) return;

    if (isPlaying) {
      // Start audio
      audioRef.current.currentTime = 0;
      audioRef.current.play().catch((error) => {
        console.error("Error playing audio:", error);
      });

      // Start pose comparison interval (every 100ms)
      comparisonIntervalRef.current = setInterval(() => {
        if (audioRef.current && motionLoaded) {
          compareCurrentPose();
        }
      }, 100);
    } else {
      // Stop audio
      audioRef.current.pause();

      // Clear comparison interval
      if (comparisonIntervalRef.current) {
        clearInterval(comparisonIntervalRef.current);
      }
    }

    return () => {
      if (comparisonIntervalRef.current) {
        clearInterval(comparisonIntervalRef.current);
      }
    };
  }, [isPlaying, motionLoaded]);

  // Handle audio end
  useEffect(() => {
    const audio = audioRef.current;
    if (!audio) return;

    const handleEnded = () => {
      setIsPlaying(false);
      if (scores.length > 0) {
        setShowSummary(true);
      }
      onEnd?.();
    };

    audio.addEventListener("ended", handleEnded);
    return () => audio.removeEventListener("ended", handleEnded);
  }, [scores, onEnd]);

  // Compare current pose
  const compareCurrentPose = async () => {
    if (!webcamVideoRef.current || !audioRef.current) return;

    const video = webcamVideoRef.current;
    if (video.readyState !== video.HAVE_ENOUGH_DATA) return;

    const timestamp = audioRef.current.currentTime;

    // Create canvas to capture frame
    const canvas = document.createElement("canvas");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    // Draw video frame to canvas
    ctx.drawImage(video, 0, 0);

    // Convert to blob
    canvas.toBlob(
      async (blob) => {
        if (!blob) return;

        const formData = new FormData();
        formData.append("file", blob, "frame.jpg");

        try {
          const response = await fetch(
            `${BACKEND_URL}/api/compare-pose-motion?timestamp=${timestamp}`,
            {
              method: "POST",
              body: formData,
            }
          );

          if (response.ok) {
            const data = await response.json();
            setScore(data.score);
            setScores((prev) => [...prev, data.score]);
            if (data.current_landmarks) {
              setCurrentLandmarks(data.current_landmarks);
            }
          } else {
            const error = await response.json();
            console.error("Error comparing pose:", error.detail);
          }
        } catch (error) {
          console.error("Error comparing pose:", error);
        }
      },
      "image/jpeg",
      0.8
    );
  };

  const handleStartStop = () => {
    if (isPlaying) {
      setIsPlaying(false);
      if (scores.length > 0) {
        setShowSummary(true);
      }
    } else {
      setScores([]);
      setScore(null);
      setIsPlaying(true);
    }
  };

  const handleRestart = () => {
    setShowSummary(false);
    setScores([]);
    setScore(null);
    setIsPlaying(true);
  };

  const getScoreColor = (score: number) => {
    if (score >= 80) return "text-green-500";
    if (score >= 60) return "text-yellow-500";
    if (score >= 40) return "text-orange-500";
    return "text-red-500";
  };

  // Show only upload UI if requested
  if (showUploadOnly) {
    return (
      <div className="w-full max-w-2xl">
        {/* Message Display */}
        {message && (
          <div className="bg-blue-500/20 backdrop-blur-md rounded-lg p-4 mb-6 text-center">
            <p className="text-white">{message}</p>
          </div>
        )}

        {/* Motion Upload Section */}
        <div className="bg-white/10 backdrop-blur-md rounded-xl p-8 text-center">
          <h2 
            className="text-4xl font-medium text-white mb-4"
            style={{
              letterSpacing: "-0.02em",
            }}
          >
            Upload Dance Moves
          </h2>
          <p 
            className="text-[rgb(156,163,175)] mb-8 text-lg"
            style={{
              letterSpacing: "-0.01em",
            }}
          >
            Upload a .pkl file containing the reference dance choreography
          </p>
          <input
            ref={motionFileInputRef}
            type="file"
            accept=".pkl"
            onChange={handleMotionUpload}
            className="hidden"
          />
          <button
            onClick={() => motionFileInputRef.current?.click()}
            className="bg-white text-[#101012] hover:bg-[rgba(255,255,255,0.9)] font-medium py-4 px-8 rounded-full transition-all duration-200 text-lg hover:cursor-pointer"
            style={{
              letterSpacing: "-0.01em",
            }}
          >
            Choose File
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="w-full">
      {/* Audio element (hidden) */}
      <audio ref={audioRef} src={audioUrl} />

      {/* Message Display */}
      {message && (
        <div className="bg-blue-500/20 backdrop-blur-md rounded-lg p-4 mb-6 text-center">
          <p className="text-white">{message}</p>
        </div>
      )}

      {/* Main Content Grid */}
      {motionLoaded && (
        <>
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
            {/* Reference Skeleton Section */}
            <div className="bg-white/10 backdrop-blur-md rounded-xl p-6">
              <h2 className="text-2xl font-semibold text-white mb-4">
                Reference Dance
              </h2>
              <div className="flex justify-center items-center">
                <AnimatedSkeleton
                  landmarks={referenceLandmarks}
                  width={400}
                  height={600}
                />
              </div>
              <div className="mt-4 text-center text-purple-200">
                Time: {currentTime.toFixed(1)}s /{" "}
                {motionMetadata?.duration.toFixed(1)}s
              </div>
            </div>

            {/* Webcam Section */}
            <div className="bg-white/10 backdrop-blur-md rounded-xl p-6">
              <h2 className="text-2xl font-semibold text-white mb-4">
                Your Dance
              </h2>
              <div className="relative">
                <WebcamCapture
                  onFrameCapture={() => {}}
                  captureInterval={500}
                  isActive={false}
                  videoRef={webcamVideoRef}
                />
                {showLandmarks && (
                  <PoseLandmarks
                    landmarks={currentLandmarks}
                    imageRef={webcamVideoRef.current}
                  />
                )}
              </div>
            </div>
          </div>

          {/* Score Display and Controls */}
          <div className="bg-white/10 backdrop-blur-md rounded-xl p-8 text-center">
            {score !== null && (
              <div className="mb-6">
                <div
                  className={`text-8xl font-bold ${getScoreColor(
                    score
                  )} drop-shadow-lg mb-2`}
                >
                  {score.toFixed(0)}
                </div>
                <p className="text-2xl text-white">Current Score</p>
              </div>
            )}

            <div className="flex gap-4 justify-center items-center flex-wrap">
              <button
                onClick={handleStartStop}
                className={`${
                  isPlaying
                    ? "bg-red-600 hover:bg-red-700"
                    : "bg-green-600 hover:bg-green-700"
                } text-white font-bold py-4 px-12 rounded-lg transition-colors text-xl hover:cursor-pointer`}
              >
                {isPlaying ? "Stop Dancing" : "Start Dancing"}
              </button>

              <button
                onClick={() => setShowLandmarks(!showLandmarks)}
                className={`${
                  showLandmarks
                    ? "bg-cyan-600 hover:bg-cyan-700"
                    : "bg-purple-600 hover:bg-purple-700"
                } text-white font-bold py-4 px-12 rounded-lg transition-colors text-xl hover:cursor-pointer`}
              >
                {showLandmarks ? "Hide Landmarks" : "Show Landmarks"}
              </button>

              <button
                onClick={() => {
                  setMotionLoaded(false);
                  setScores([]);
                  setScore(null);
                  setIsPlaying(false);
                }}
                className="bg-gray-600 hover:bg-gray-700 text-white font-bold py-4 px-12 rounded-lg transition-colors text-xl"
              >
                Change Motion
              </button>
            </div>

            {!isPlaying && scores.length === 0 && (
              <p className="text-purple-200 mt-4">
                Click "Start Dancing" to begin the game!
              </p>
            )}
          </div>
        </>
      )}

      {/* Score Summary Modal */}
      {showSummary && (
        <ScoreSummary
          scores={scores}
          onRestart={handleRestart}
          onClose={() => setShowSummary(false)}
        />
      )}
    </div>
  );
}

