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

import Icon from "@/components/icon";
import { useStore } from "@/store";
import type { Song } from "@/types";

import styles from "./styles.module.scss";

interface AudioPlayerProps extends Song {
  preload?: "auto" | "metadata" | "none";
  className?: string;
  style?: React.CSSProperties;
}

export default function AudioPlayer({
  src,
  preload = "metadata",
  className,
  ...props
}: AudioPlayerProps) {
  const activeAudioEl = useStore.use.activeAudioEl();
  const setActiveAudioEl = useStore.use.setActiveAudioEl();
  const audioRef = useRef<HTMLAudioElement>(null);
  const progressBarContainerRef = useRef<HTMLDivElement>(null);
  const progressBarWaveformRef = useRef<SVGSVGElement>(null);
  const [isReady, setIsReady] = useState(false);
  const [shouldPlay, setShouldPlay] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);
  const [progress, setProgress] = useState(0);
  const [waveformScale, setWaveformScale] = useState(1);

  const toggleAudio = (
    event: React.MouseEvent<HTMLButtonElement | HTMLDivElement>,
  ) => {
    event.preventDefault();
    setShouldPlay(!shouldPlay);
  };

  const handlePlay = () => {
    const audio = audioRef.current;
    if (!audio) return;
    if (!activeAudioEl || activeAudioEl.id !== audio.id)
      setActiveAudioEl(audio);
    setIsPlaying(true);
  };

  const handlePause = () => {
    const audio = audioRef.current;
    if (!audio) return;
    if (activeAudioEl && activeAudioEl.id === audio.id) setActiveAudioEl(null);
    setIsPlaying(false);
  };

  const handleTimeUpdate = () => {
    const audio = audioRef.current;
    if (!audio) return;
    setProgress(audio.currentTime / audio.duration);
  };

  const handleEnded = () => {
    // Reset state when audio finishes playing
    setIsPlaying(false);
    setShouldPlay(false);
    setProgress(0);
  };

  const handleProgressBarClick = (e: React.MouseEvent<HTMLDivElement>) => {
    const progressBarContainer = progressBarContainerRef.current;
    const audio = audioRef.current;
    if (!isReady || !shouldPlay || !progressBarContainer || !audio) return;

    const mouseOffsetFromLeft =
      e.clientX - progressBarContainer.getBoundingClientRect().left;
    const clickPositionPercentage =
      mouseOffsetFromLeft / progressBarContainer.offsetWidth;
    const newTime = audio.duration * clickPositionPercentage;

    audio.currentTime = newTime;
  };

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

    const handleLoad = () => setIsReady(true);
    const handleError = () => setIsReady(false);

    audio.addEventListener("canplaythrough", handleLoad);
    audio.addEventListener("error", handleError);
    return () => {
      audio.removeEventListener("canplaythrough", handleLoad);
      audio.removeEventListener("error", handleError);
    };
  }, []);

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

    if (shouldPlay) {
      audio.play();
    } else {
      audio.pause();
    }
  }, [shouldPlay]);

  useEffect(() => {
    const progressBarContainer = progressBarContainerRef.current;
    const progressBarWaveform = progressBarWaveformRef.current;
    if (!progressBarContainer || !progressBarWaveform) return;

    const updateWaveformScale = () => {
      const scaleFactor =
        progressBarContainer.offsetWidth / progressBarWaveform.getBBox().width;
      const visualAdjustmentFactor = 1.1; // Adjust for visual gaps
      setWaveformScale(scaleFactor * visualAdjustmentFactor);
    };

    updateWaveformScale();

    window.addEventListener("resize", updateWaveformScale);
    return () => {
      window.removeEventListener("resize", updateWaveformScale);
    };
  }, []);

  return (
    <div
      className={clsx(styles.audioPlayer, className, {
        [styles.notAllowed]: !isReady,
      })}
      onClick={!isPlaying ? toggleAudio : undefined}
    >
      <audio
        className={styles.audio}
        ref={audioRef}
        preload={preload}
        onPlay={handlePlay}
        onPause={handlePause}
        onEnded={handleEnded}
        onTimeUpdate={handleTimeUpdate}
        {...props}
      >
        {Array.isArray(src) ? (
          src.map((source, index) => <source key={index} src={source} />)
        ) : (
          <source src={src} />
        )}
      </audio>
      <button
        className={styles.playPauseButton}
        onClick={toggleAudio}
        aria-label={isPlaying ? "Pause audio" : "Play audio"}
      >
        <span className={styles.iconGroup}>
          <Icon
            id="pause-icon"
            className={clsx(styles.icon, {
              [styles.visible]: isPlaying,
            })}
            variant="pause"
          />
          <Icon
            id="play-icon"
            className={clsx(styles.icon, {
              [styles.visible]: !isPlaying,
              [styles.notAllowed]: !isReady,
            })}
            variant="play"
          />
        </span>
      </button>
      <div
        ref={progressBarContainerRef}
        className={clsx(styles.progressBarContainer, {
          [styles.active]: isPlaying,
        })}
        onClick={handleProgressBarClick}
      >
        <div
          className={clsx(styles.progressBar, styles.mask)}
          style={{
            transform: `scaleX(${
              isPlaying && progress > 0 ? 100 - progress * 100 : 0
            }%)`,
          }}
        />
        <Icon
          ref={progressBarWaveformRef}
          className={clsx(styles.progressBar, styles.waveform)}
          style={{ transform: `scaleX(${waveformScale})` }}
          variant="waveform"
        />
      </div>
    </div>
  );
}
