"use client";

import { useState, useRef, useEffect } from "react";
import { Button } from "@cap/ui";
import { trackEvent } from "@/app/utils/analytics";

const SPEED_OPTIONS = [
  { value: 0.25, label: "0.25x (Very Slow)" },
  { value: 0.5, label: "0.5x (Slow)" },
  { value: 0.75, label: "0.75x (Slightly Slow)" },
  { value: 1.25, label: "1.25x (Slightly Fast)" },
  { value: 1.5, label: "1.5x (Fast)" },
  { value: 2, label: "2x (Very Fast)" },
  { value: 3, label: "3x (Ultra Fast)" },
];

const SUPPORTED_VIDEO_FORMATS = ["mp4", "webm", "mov", "avi", "mkv"];

export const SpeedController = () => {
  const [file, setFile] = useState<File | null>(null);
  const [isProcessing, setIsProcessing] = useState(false);
  const [progress, setProgress] = useState(0);
  const [outputUrl, setOutputUrl] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [selectedSpeed, setSelectedSpeed] = useState<number>(1.5);
  const [videoInfo, setVideoInfo] = useState<{
    duration: number;
    dimensions: string;
  } | null>(null);
  const [isSafari, setIsSafari] = useState(false);
  const [selectedMimeType, setSelectedMimeType] = useState<string>("");

  const fileInputRef = useRef<HTMLInputElement>(null);
  const videoPreviewRef = useRef<HTMLVideoElement | null>(null);
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const recordedChunksRef = useRef<Blob[]>([]);

  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFile = e.target.files?.[0];
    if (selectedFile) {
      validateAndSetFile(selectedFile);
    }
  };

  const validateAndSetFile = (selectedFile: File) => {
    setError(null);
    setOutputUrl(null);
    setVideoInfo(null);

    const isVideoFile =
      selectedFile.type.startsWith("video/") ||
      SUPPORTED_VIDEO_FORMATS.some((format) =>
        selectedFile.name.toLowerCase().endsWith(`.${format}`)
      );

    if (!isVideoFile) {
      setError("Please select a valid video file.");
      trackEvent("speed_controller_invalid_file_type", {
        fileType: selectedFile.type,
      });
      return;
    }

    if (selectedFile.size > 500 * 1024 * 1024) {
      setError("File size exceeds 500MB limit.");
      trackEvent("speed_controller_file_too_large", {
        fileSize: selectedFile.size,
      });
      return;
    }

    setFile(selectedFile);
    trackEvent("speed_controller_file_selected", {
      fileSize: selectedFile.size,
      fileType: selectedFile.type,
    });

    const videoElement = document.createElement("video");
    videoElement.preload = "metadata";

    videoElement.onloadedmetadata = () => {
      URL.revokeObjectURL(videoElement.src);
      const duration = videoElement.duration;
      const dimensions = `${videoElement.videoWidth}x${videoElement.videoHeight}`;
      setVideoInfo({ duration, dimensions });
    };

    videoElement.src = URL.createObjectURL(selectedFile);
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(true);
  };

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);

    const droppedFile = e.dataTransfer.files[0];
    if (droppedFile) {
      validateAndSetFile(droppedFile);
    }
  };

  const processVideo = async () => {
    if (!file) return;

    setIsProcessing(true);
    setError(null);
    setProgress(0);

    const action = selectedSpeed < 1 ? "slowing_down" : "speeding_up";
    trackEvent(`speed_controller_${action}_started`, {
      fileSize: file.size,
      fileName: file.name,
      speedFactor: selectedSpeed,
    });

    try {
      console.log(`Starting video speed adjustment: ${selectedSpeed}x`);
      console.log(`Input file: ${file.name}, size: ${file.size} bytes`);

      const fileUrl = URL.createObjectURL(file);
      await adjustVideoSpeed(fileUrl);
      URL.revokeObjectURL(fileUrl);
    } catch (err: any) {
      console.error("Detailed processing error:", err);

      let errorMessage = "Processing failed: ";
      if (err.message) {
        errorMessage += err.message;
      } else if (typeof err === "string") {
        errorMessage += err;
      } else {
        errorMessage += "Unknown error occurred during processing";
      }

      setError(errorMessage);

      trackEvent(`speed_controller_${action}_failed`, {
        fileSize: file.size,
        fileName: file.name,
        error: err.message || "Unknown error",
        speedFactor: selectedSpeed,
      });
    } finally {
      setIsProcessing(false);
    }
  };

  const adjustVideoSpeed = async (videoUrl: string): Promise<void> => {
    return new Promise((resolve, reject) => {
      const video = document.createElement("video");
      videoRef.current = video;
      video.src = videoUrl;
      video.muted = false;

      video.oncanplay = async () => {
        try {
          const canvas = document.createElement("canvas");
          canvas.width = video.videoWidth;
          canvas.height = video.videoHeight;
          const ctx = canvas.getContext("2d", { alpha: false });

          if (!ctx) {
            throw new Error("Failed to create canvas context");
          }

          let inputFormat = "video/webm";
          if (file?.type) {
            inputFormat = file.type;
          } else if (file?.name) {
            const extension = file.name.split(".").pop()?.toLowerCase();
            if (extension === "mp4") inputFormat = "video/mp4";
            else if (extension === "webm") inputFormat = "video/webm";
            else if (extension === "mov") inputFormat = "video/quicktime";
          }

          let mimeTypes: string[] = [];

          if (inputFormat.includes("mp4")) {
            mimeTypes = [
              "video/mp4",
              "video/webm;codecs=vp9,opus",
              "video/webm;codecs=vp8,opus",
              "video/webm;codecs=vp9",
              "video/webm;codecs=vp8",
              "video/webm",
            ];
          } else {
            mimeTypes = [
              "video/webm;codecs=vp9,opus",
              "video/webm;codecs=vp8,opus",
              "video/webm;codecs=vp9",
              "video/webm;codecs=vp8",
              "video/webm",
              "video/mp4",
            ];
          }

          let selectedMimeType = "";
          for (const type of mimeTypes) {
            if (MediaRecorder.isTypeSupported(type)) {
              selectedMimeType = type;
              break;
            }
          }

          if (!selectedMimeType) {
            throw new Error(
              "None of the media formats are supported by this browser"
            );
          }

          setSelectedMimeType(selectedMimeType);
          console.log(
            `Input format: ${inputFormat}, Selected output format: ${selectedMimeType}`
          );

          let includeAudio = true;
          const supportsAudio = MediaRecorder.isTypeSupported(
            selectedMimeType +
              (selectedMimeType.includes("codecs=") ? ",opus" : ";codecs=opus")
          );

          if (!supportsAudio) {
            console.warn(
              "Selected MIME type does not support audio: " + selectedMimeType
            );
            includeAudio = false;
          }

          const stream = canvas.captureStream(60);

          video.muted = false;
          if (includeAudio) {
            try {
              const audioContext = new AudioContext();
              const source = audioContext.createMediaElementSource(video);
              const destination = audioContext.createMediaStreamDestination();
              source.connect(destination);

              destination.stream.getAudioTracks().forEach((track) => {
                stream.addTrack(track);
              });
            } catch (audioErr) {
              console.warn("Could not add audio track", audioErr);
            }
          }

          const recorder = new MediaRecorder(stream, {
            mimeType: selectedMimeType,
            videoBitsPerSecond: 5000000,
          });
          mediaRecorderRef.current = recorder;
          recordedChunksRef.current = [];

          recorder.ondataavailable = (e) => {
            if (e.data.size > 0) {
              recordedChunksRef.current.push(e.data);
            }
          };

          recorder.onstop = () => {
            const chunks = recordedChunksRef.current;
            const blob = new Blob(chunks, {
              type: selectedMimeType.split(";")[0],
            });
            const url = URL.createObjectURL(blob);

            setOutputUrl(url);

            trackEvent(
              `speed_controller_${
                selectedSpeed < 1 ? "slowing_down" : "speeding_up"
              }_completed`,
              {
                fileSize: file!.size,
                fileName: file!.name,
                outputSize: blob.size,
                speedFactor: selectedSpeed,
              }
            );

            videoRef.current = null;
            mediaRecorderRef.current = null;
            resolve();
          };

          recorder.start(1000);

          video.playbackRate = selectedSpeed;

          const finishProcessing = () => {
            if (recorder.state === "recording") {
              recorder.stop();
            }
            setProgress(100);
            cancelAnimationFrame(animationFrameId);
          };

          const totalDuration = video.duration / selectedSpeed;
          let lastProgress = 0;
          let stuckCounter = 0;
          let isFrameStuck = false;
          let lastFrameTime = 0;
          let animationFrameId: number;

          const renderFrame = () => {
            if (video.readyState >= 2) {
              const currentTime = video.currentTime;
              const currentProgress = (currentTime / video.duration) * 100;

              if (currentTime !== lastFrameTime) {
                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
                lastFrameTime = currentTime;
                isFrameStuck = false;
              } else {
                isFrameStuck = true;
              }

              if (Math.abs(currentProgress - lastProgress) < 0.1) {
                stuckCounter++;
                if (stuckCounter > 180 && currentProgress > 95) {
                  console.log(
                    "Progress appears to be stuck, forcing completion"
                  );
                  finishProcessing();
                  return;
                }
              } else {
                stuckCounter = 0;
                lastProgress = currentProgress;
              }

              setProgress(Math.min(Math.round(currentProgress), 99));
            }

            if (video.ended || (isFrameStuck && stuckCounter > 300)) {
              finishProcessing();
            } else {
              animationFrameId = requestAnimationFrame(renderFrame);
            }
          };

          video
            .play()
            .then(() => {
              animationFrameId = requestAnimationFrame(renderFrame);
            })
            .catch((err) => {
              console.error("Error playing video:", err);
              reject(err);
            });

          const safetyTimeout = setTimeout(() => {
            if (recorder.state === "recording") {
              console.log("Safety timeout reached, forcing completion");
              finishProcessing();
            }
          }, totalDuration * 1000 + 5000);

          video.onended = () => {
            clearTimeout(safetyTimeout);
            setTimeout(() => {
              finishProcessing();
            }, 500);
          };
        } catch (err) {
          reject(err);
        }
      };

      video.onerror = () => {
        reject(new Error("Error loading video"));
      };
    });
  };

  const handleDownload = () => {
    if (!outputUrl || !file) return;

    const dotIndex = file.name.lastIndexOf(".");
    const baseName =
      dotIndex !== -1 ? file.name.substring(0, dotIndex) : file.name;

    const chunks = recordedChunksRef.current;
    let extension = "webm";

    if (chunks.length > 0) {
      const firstChunk = chunks[0];
      if (firstChunk) {
        const type = firstChunk.type;
        if (type.includes("mp4")) {
          extension = "mp4";
        } else if (type.includes("webm")) {
          extension = "webm";
        } else if (type.includes("quicktime") || type.includes("mov")) {
          extension = "mov";
        }
      }
    } else {
      if (selectedMimeType.includes("mp4")) {
        extension = "mp4";
      } else if (selectedMimeType.includes("webm")) {
        extension = "webm";
      } else if (
        selectedMimeType.includes("quicktime") ||
        selectedMimeType.includes("mov")
      ) {
        extension = "mov";
      }
    }

    const downloadFileName = `${baseName}_${selectedSpeed}x.${extension}`;

    trackEvent(`speed_controller_download_clicked`, {
      fileName: downloadFileName,
      speedFactor: selectedSpeed,
    });

    const link = document.createElement("a");
    link.href = outputUrl;
    link.download = downloadFileName;
    link.click();
  };

  const resetController = () => {
    if (outputUrl) {
      URL.revokeObjectURL(outputUrl);
    }

    if (
      mediaRecorderRef.current &&
      mediaRecorderRef.current.state !== "inactive"
    ) {
      mediaRecorderRef.current.stop();
    }

    if (videoRef.current) {
      videoRef.current.pause();
      videoRef.current.src = "";
    }

    setFile(null);
    setOutputUrl(null);
    setProgress(0);
    setError(null);
    setVideoInfo(null);
    recordedChunksRef.current = [];

    trackEvent(`speed_controller_reset`);

    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
  };

  const formatDuration = (seconds: number) => {
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = Math.floor(seconds % 60);
    return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
  };

  const getEstimatedOutputDuration = () => {
    if (!videoInfo) return null;
    const estimatedDuration = videoInfo.duration / selectedSpeed;
    return formatDuration(estimatedDuration);
  };

  useEffect(() => {
    const isSafariBrowser = /^((?!chrome|android).)*safari/i.test(
      navigator.userAgent
    );
    setIsSafari(isSafariBrowser);
  }, []);

  return (
    <div className="w-full">
      <h2 className="text-2xl font-semibold text-center mb-6">
        {selectedSpeed < 1 ? "Slow Down" : "Speed Up"} Your Video
      </h2>

      <div className="mb-6">
        <label className="block text-sm font-medium text-gray-700 mb-2">
          Select Speed
        </label>
        <div className="flex flex-wrap gap-2 justify-center">
          {SPEED_OPTIONS.map((option) => (
            <button
              key={option.value}
              onClick={() => setSelectedSpeed(option.value)}
              className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
                selectedSpeed === option.value
                  ? "bg-blue-600 text-white"
                  : "bg-gray-200 text-gray-800 hover:bg-gray-300"
              }`}
            >
              {option.label}
            </button>
          ))}
        </div>
      </div>

      <div
        className={`border-2 border-dashed rounded-lg p-8 mb-6 flex flex-col items-center justify-center cursor-pointer transition-colors ${
          isDragging
            ? "border-blue-500 bg-blue-50"
            : "border-gray-300 hover:border-blue-400"
        }`}
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
        onClick={() => fileInputRef.current?.click()}
        style={{ minHeight: "200px" }}
      >
        <input
          type="file"
          accept="video/*"
          className="hidden"
          onChange={handleFileChange}
          ref={fileInputRef}
        />

        <div className="text-center">
          {!file ? (
            <>
              <svg
                className="mx-auto h-12 w-12 text-gray-400 mb-3"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
                />
              </svg>
              <p className="text-lg font-medium text-gray-700">
                Drag and drop your video file here
              </p>
              <p className="text-sm text-gray-500 mt-1">
                or click to browse (max 500MB)
              </p>
            </>
          ) : (
            <>
              <svg
                className="mx-auto h-12 w-12 text-green-500 mb-3"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M5 13l4 4L19 7"
                />
              </svg>
              <p className="text-lg font-medium text-gray-700">{file.name}</p>
              <p className="text-sm text-gray-500 mt-1">
                {(file.size / (1024 * 1024)).toFixed(2)} MB
              </p>
              {videoInfo && (
                <div className="mt-3 text-sm text-gray-600">
                  <p>Duration: {formatDuration(videoInfo.duration)}</p>
                  <p>Resolution: {videoInfo.dimensions}</p>
                  <p className="mt-2 font-medium">
                    Estimated output duration: {getEstimatedOutputDuration()}
                  </p>
                </div>
              )}
            </>
          )}
        </div>
      </div>

      {error && (
        <div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg text-red-600">
          {error}
        </div>
      )}

      {isProcessing && (
        <div className="mb-6">
          <p className="text-center text-gray-700 mb-2">
            Processing... {progress}%
          </p>
          <div className="w-full bg-gray-200 rounded-full h-2">
            <div
              className="bg-blue-600 h-2 rounded-full transition-all"
              style={{ width: `${progress}%` }}
            ></div>
          </div>
        </div>
      )}

      {outputUrl && (
        <div className="mb-6 p-5 bg-green-50 border border-green-200 rounded-lg">
          <p className="text-green-700 font-medium mb-3">
            Video {selectedSpeed < 1 ? "slowed down" : "sped up"} successfully!
          </p>
          <video
            ref={videoPreviewRef}
            src={outputUrl}
            controls
            className="w-full rounded-lg mb-4 bg-black"
            style={{ maxHeight: "400px" }}
          ></video>
          <div className="flex flex-col sm:flex-row space-y-3 sm:space-y-0 sm:space-x-3">
            <Button
              variant="primary"
              onClick={handleDownload}
              className="w-full"
            >
              Download {selectedSpeed}x Video
            </Button>
          </div>
        </div>
      )}

      <div className="flex flex-col sm:flex-row space-y-3 sm:space-y-0 sm:space-x-3">
        {file && !isProcessing && !outputUrl && (
          <Button
            variant="primary"
            onClick={processVideo}
            disabled={isProcessing}
            className="w-full"
          >
            {selectedSpeed < 1 ? "Slow Down" : "Speed Up"} Video (
            {selectedSpeed}x)
          </Button>
        )}

        {(file || outputUrl) && (
          <Button
            variant="white"
            onClick={resetController}
            disabled={isProcessing}
            className="w-full"
          >
            {outputUrl ? "Process Another Video" : "Reset"}
          </Button>
        )}
      </div>

      <div className="mt-8 pt-6 border-t border-gray-200 text-sm text-gray-500 text-center">
        <p>
          This tool works entirely in your browser. Your videos are never
          uploaded to any server.
        </p>
        <p className="mt-1">
          Powered by modern browser APIs like MediaRecorder and Canvas for
          efficient video processing.
        </p>
        {isSafari && (
          <div className="mt-3 p-3 bg-yellow-50 border border-yellow-200 rounded-md text-yellow-700">
            <p>
              <strong>Safari Compatibility Notice:</strong> Safari has limited
              support for some video processing features. For best results,
              consider using Chrome or Firefox.
            </p>
          </div>
        )}
      </div>
    </div>
  );
};
