import React, {
  useCallback,
  useEffect,
  useLayoutEffect,
  useRef,
  useState,
} from "react";
import "./GenresDisk.css";
import { fetchAudioUrl, getClipTitlesAndIDsByGenre } from "../utils/audioUtils";
import { capitalizeGenre } from "../utils/utils";

type GenreData = {
  genre: string;
  angle: number;
  radius: number;
  width: number;
  height: number;
  x: number;
  y: number;
  color: string;
};

type GenresDiskProps = {
  data: GenreData[];
  onGenreSelect: (genre: string, audioUrl: string, color: string) => void;
  selectedGenreName?: string;
  isPlaying?: boolean;
  onSwipeStart?: () => void;
};

const useDiskRotator = (disk: HTMLDivElement | null) => {
  const requestRef = useRef<any>();

  const animate = (time: any) => {
    requestRef.current = requestAnimationFrame(animate);
  };

  useLayoutEffect(() => {
    if (disk) {
      requestRef.current = requestAnimationFrame(animate);

      return () => {
        cancelAnimationFrame(requestRef.current);
      };
    }
  }, [disk]);
};

const GenresDiskMobile: React.FC<GenresDiskProps> = ({
  data,
  onGenreSelect,
  selectedGenreName,
  isPlaying,
  onSwipeStart,
}) => {
  const isMobileDevice = () => {
    return window.innerWidth <= 768;
  };

  // Need this to ensure animation does not pause when switching pages:
  const [animationKey, setAnimationKey] = useState(0);

  useEffect(() => {
    const restartAnimation = () => {
      setAnimationKey((prevKey) => prevKey + 1);
    };

    restartAnimation();

    const handleVisibilityChange = () => {
      if (document.visibilityState === "visible") {
        restartAnimation();
      }
    };

    document.addEventListener("visibilitychange", handleVisibilityChange);

    return () => {
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, [data]);
  //**************************************************************************

  const [hoveredGenre, setHoveredGenre] = useState<number | null>(null);

  const diskRef = useRef<HTMLDivElement | null>(null);

  // useDiskRotator(diskRef.current);

  const [rotation, setRotation] = useState(() => Math.random() * 360);

  const [audioURL, setAudioURL] = useState("");

  const [startX, setStartX] = useState(0);
  const [startY, setStartY] = useState(0);
  const [startRotation, setStartRotation] = useState(0);

  const handleTouchStart = useCallback(
    (e: any) => {
      if (!diskRef.current || !diskRef.current.contains(e.target)) {
        return;
      }
      setIsInteracting(true);

      // e.preventDefault();
      setStartX(e.touches[0].clientX);
      setStartY(e.touches[0].clientY);
      setStartRotation(rotation);
    },
    [rotation]
  );

  const handleTouchEnd = useCallback(
    (e: any) => {
      if (!diskRef.current) {
        return;
      }

      // e.preventDefault();
      const endX = e.changedTouches[0].clientX;
      const endY = e.changedTouches[0].clientY;

      const deltaX = endX - startX;
      const deltaY = endY - startY;
      const distance = Math.sqrt(deltaX ** 2 + deltaY ** 2);

      // if (distance > 10) {
      //   e.preventDefault();
      //   setRotation((prevRotation) => (prevRotation + deltaX * 0.5) % 360);
      // }

      if (onSwipeStart) {
        onSwipeStart();
      }
      setIsInteracting(false);
    },
    [startX, startY, diskRef.current]
  );

  function calculateAngle(A: any, B: any, C: any) {
    // Each point is an object with x and y: { x: ..., y: ... }

    // Calculate the vector lengths
    const AB = Math.sqrt(Math.pow(B.x - A.x, 2) + Math.pow(B.y - A.y, 2));
    const BC = Math.sqrt(Math.pow(B.x - C.x, 2) + Math.pow(B.y - C.y, 2));
    const AC = Math.sqrt(Math.pow(C.x - A.x, 2) + Math.pow(C.y - A.y, 2));

    // Use the law of cosines to calculate the angle at B
    const angleRadians = Math.acos(
      (AB * AB + BC * BC - AC * AC) / (2 * AB * BC)
    );

    // Convert radians to degrees
    const angleDegrees = angleRadians * (180 / Math.PI);

    return angleDegrees;
  }

  const handleTouchMove = useCallback(
    (e: any) => {
      if (!diskRef.current) {
        return;
      }

      // e.preventDefault();
      const endX = e.changedTouches[0].clientX;
      const endY = e.changedTouches[0].clientY;
      const rect = diskRef.current.getBoundingClientRect();

      let rotationDelta = calculateAngle(
        { x: startX, y: startY },
        { x: rect.x, y: rect.y },
        { x: endX, y: endY }
      );

      const deltaX = endX - startX;
      const deltaY = endY - startY;

      const distance = Math.sqrt(deltaX ** 2 + deltaY ** 2);

      if (endY < startY) {
        rotationDelta *= -1;
      }

      // if (distance > 10) {
      e.preventDefault();
      setRotation((prevRotation) => (startRotation + rotationDelta * 1) % 360);
      // }

      if (onSwipeStart) {
        onSwipeStart();
      }
      // setIsInteracting(false);
    },
    [startX, startY, startRotation, diskRef.current]
  );

  useEffect(() => {
    const handleTouchStartWrapper = (e: any) => handleTouchStart(e);
    const handleTouchEndWrapper = (e: any) => handleTouchEnd(e);

    const handleTouchMoveWrapper = (e: any) => {
      // console.log("here", e);
      handleTouchMove(e);
    };

    window.addEventListener("touchstart", handleTouchStartWrapper, {
      passive: false,
    });

    window.addEventListener("touchmove", handleTouchMoveWrapper, {
      passive: false,
    });

    window.addEventListener("touchend", handleTouchEndWrapper, {
      passive: false,
    });

    return () => {
      window.removeEventListener("touchstart", handleTouchStartWrapper);
      window.removeEventListener("touchmove", handleTouchMoveWrapper);
      window.removeEventListener("touchend", handleTouchEndWrapper);
    };
  }, [handleTouchStart, handleTouchEnd, handleTouchMove]);

  // ***************SCROLL EVENTS FOR DESKTOP AND ROTATION:***************
  const [isInteracting, setIsInteracting] = useState(false);

  useEffect(() => {
    if (isInteracting) {
      return;
    }

    const rotateInterval = setInterval(() => {
      const rotationIncrement = isMobileDevice() ? 0 : 0.3;
      setRotation((prevRotation) => (prevRotation + rotationIncrement) % 360);
    }, 500);

    return () => clearInterval(rotateInterval);
  }, [isInteracting]);

  useEffect(() => {
    const handleWheel = (event: any) => {
      // event.preventDefault();
      setIsInteracting(true);

      const scrollAmount = event.deltaY;
      const rotationChange = -scrollAmount * 0.1;

      setRotation((prevRotation) => {
        const newRotation = (prevRotation + rotationChange) % 360;
        return newRotation;
      });

      setTimeout(() => {
        setIsInteracting(false);
      }, 100);
    };

    window.addEventListener("wheel", handleWheel, { passive: false });

    return () => window.removeEventListener("wheel", handleWheel);
  }, []);

  useEffect(() => {
    if (diskRef.current) {
      diskRef.current.style.transform = `rotate(${rotation}deg)`;
    }
  }, [rotation]);

  // ***********************************************************************

  useEffect(() => {
    if (selectedGenreName) {
      setIsInteracting(true);

      const genreData = data.find(
        (item) => item.genre.toLowerCase() === selectedGenreName.toLowerCase()
      );
      if (genreData) {
        let targetRotation = 360 - genreData.angle;

        const currentRotationNormalized = ((rotation % 360) + 360) % 360;
        let rotationDifference = targetRotation - currentRotationNormalized;
        rotationDifference = ((rotationDifference + 540) % 360) - 180;

        targetRotation = currentRotationNormalized + rotationDifference;

        setRotation(targetRotation);

        setTimeout(() => {
          setIsInteracting(false);
        }, 1000);
      }
    }
  }, [selectedGenreName, data]);

  const handleGenreClick = async (genre: string, color: string) => {
    const clipTitlesAndIDsByGenre = getClipTitlesAndIDsByGenre();
    const normalizedGenre = genre.toLowerCase().trim();
    const clipsForGenre = clipTitlesAndIDsByGenre[normalizedGenre];

    if (clipsForGenre && clipsForGenre.length > 0) {
      const [firstSongTitle, firstClipId] = clipsForGenre[0];
      const firstSongUrl = await fetchAudioUrl(firstClipId);

      if (firstSongUrl) {
        const capitalizedGenre = capitalizeGenre(genre);
        onGenreSelect(capitalizedGenre, firstSongUrl, color);
        setAudioURL(firstSongUrl);

        // Comment back in for changing URL to include genre and song title:
        // const formattedGenre = genre.replace(/\s+/g, "_");
        // const formattedSongTitle = firstSongTitle?.replace(/\s+/g, "_");
        // const newHash = `${encodeURIComponent(
        //   formattedGenre
        // )}_${encodeURIComponent(formattedSongTitle as string)}`;
        // window.location.hash = `${newHash}`;
      } else {
        console.error(
          `Audio URL for clip ID ${firstClipId} could not be fetched.`
        );
      }
    } else {
      console.error(`No clips found for genre: ${genre}`);
    }
  };

  return (
    <div className="diskContainer">
      <div
        className="disk"
        key={animationKey}
        ref={diskRef}
        style={{
          transform: `rotate(${rotation}deg)`,
          // transform: `rotate(${specificRotation + continuousRotation}deg)`,
          transformOrigin: "center",
          transition: "transform 0.4s ease-out",
        }}
        tabIndex={0}
      >
        {data.map((item, index) => {
          const isHighlighted =
            selectedGenreName?.trim().toLowerCase() ===
            item.genre.trim().toLowerCase();

          return (
            <div
              key={index}
              className="genreItem"
              onClick={() => handleGenreClick(item.genre, item.color)}
              style={{
                position: "absolute",
                width: `${item.width + 90}px`,
                height: `${item.height}px`,
                transform: `translate(-50%, -50%) rotate(${item.angle}deg) translate(${item.radius}px)`,
                fontFamily: "PP Neue Montreal",
                textAlign: "center",
                cursor: "pointer",
                transition: "all 0.3s ease",
                fontSize: isHighlighted ? "18px" : "14px",
                lineHeight: `${item.height}px`,
                color: isHighlighted ? "white" : item.color,
                backgroundColor: isHighlighted ? item.color : "transparent",
                borderRadius: isHighlighted ? "20px" : "",
                padding: isHighlighted ? "5px" : "",
                zIndex: isHighlighted ? 10000 : 1,
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
              }}
              onMouseEnter={(e) => {
                if (
                  item.genre.trim().toLowerCase() !==
                  selectedGenreName?.trim().toLowerCase()
                ) {
                  e.currentTarget.style.fontSize = "18px";
                  e.currentTarget.style.backgroundColor = item.color;
                  e.currentTarget.style.borderRadius = "20px";
                  e.currentTarget.style.padding = "5px";
                  e.currentTarget.style.color = "white";
                  e.currentTarget.style.position = "absolute";
                  e.currentTarget.style.zIndex = "10000";
                  e.currentTarget.style.backgroundColor = item.color;
                  e.currentTarget.style.whiteSpace = "nowrap";
                  e.currentTarget.style.overflow = "hidden";
                  e.currentTarget.style.textOverflow = "ellipsis";
                }
              }}
              onMouseLeave={(e) => {
                if (
                  item.genre.trim().toLowerCase() !==
                  selectedGenreName?.trim().toLowerCase()
                ) {
                  e.currentTarget.style.backgroundColor = "transparent";
                  e.currentTarget.style.fontSize = "14px";
                  e.currentTarget.style.backgroundColor = "";
                  e.currentTarget.style.borderRadius = "";
                  e.currentTarget.style.padding = "";
                  e.currentTarget.style.color = item.color;
                  e.currentTarget.style.zIndex = "1";
                }
              }}
            >
              {isHighlighted && isPlaying && (
                <div style={{ marginRight: "12px" }}>
                  <svg
                    width="12"
                    height="13"
                    viewBox="0 0 12 13"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <rect
                      className="bar bar1"
                      x="3.26929"
                      y="0.445496"
                      width="2"
                      height="12"
                      transform="rotate(-1.76 3.26929 0.445496)"
                      fill="white"
                    />
                    <rect
                      className="bar bar2"
                      x="6.41528"
                      y="5.15097"
                      width="2"
                      height="7.2"
                      transform="rotate(-1.76 6.41528 5.15097)"
                      fill="white"
                    />
                    <rect
                      className="bar bar3"
                      x="9.34033"
                      y="2.66003"
                      width="2"
                      height="9.6"
                      transform="rotate(-1.76 9.34033 2.66003)"
                      fill="white"
                    />
                    <rect
                      className="bar bar4"
                      x="0.528809"
                      y="8.93362"
                      width="2"
                      height="3.6"
                      transform="rotate(-1.76 0.528809 8.93362)"
                      fill="white"
                    />
                  </svg>
                </div>
              )}

              {item.genre}
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default GenresDiskMobile;
