import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import "./index.scss";

function formatAudioTime(seconds: number): string {
  const safe = Number.isFinite(seconds) && seconds > 0 ? seconds : 0;
  const total = Math.floor(safe);
  const mins = Math.floor(total / 60);
  const secs = total % 60;
  return `${String(mins).padStart(2, "0")}：${String(secs).padStart(2, "0")}`;
}

export type AssetAudioPlayerHandle = {
  togglePlay: () => void;
};

export interface AssetAudioPlayerProps {
  src: string;
  resetKey?: string | number;
  autoPlay?: boolean;
  autoAdvanceOnEnded?: boolean;
  className?: string;
  onPlayingChange?: (playing: boolean) => void;
  canGoPrevious?: boolean;
  canGoNext?: boolean;
  onPrevious?: () => void;
  onNext?: () => void;
}

export const AssetAudioPlayer = forwardRef<AssetAudioPlayerHandle, AssetAudioPlayerProps>(function AssetAudioPlayer(
  { src, resetKey, autoPlay = false, autoAdvanceOnEnded = false, className, onPlayingChange, canGoPrevious = false, canGoNext = false, onPrevious, onNext },
  forwardedRef,
) {
  const { t } = useTranslation();
  const audioRef = useRef<HTMLAudioElement>(null);
  const progressTrackRef = useRef<HTMLDivElement>(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);

  const voiceSrc = String(src ?? "").trim();

  useEffect(() => {
    setIsPlaying(false);
    setCurrentTime(0);
    setDuration(0);
    const audio = audioRef.current;
    if (audio) {
      audio.pause();
      audio.currentTime = 0;
    }
  }, [voiceSrc, resetKey]);

  useEffect(() => {
    if (!autoPlay || !voiceSrc) return;
    const audio = audioRef.current;
    if (!audio) return;
    void audio.play().catch(() => { });
  }, [autoPlay, voiceSrc, resetKey]);

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

    const syncDuration = () => {
      setDuration(Number.isFinite(audio.duration) ? audio.duration : 0);
    };
    const onTimeUpdate = () => setCurrentTime(audio.currentTime);
    const onEnded = () => {
      setIsPlaying(false);
      onPlayingChange?.(false);
      if (autoAdvanceOnEnded && canGoNext && onNext) {
        onNext();
      }
    };
    const onPlay = () => {
      setIsPlaying(true);
      onPlayingChange?.(true);
    };
    const onPause = () => {
      setIsPlaying(false);
      onPlayingChange?.(false);
    };

    audio.addEventListener("timeupdate", onTimeUpdate);
    audio.addEventListener("loadedmetadata", syncDuration);
    audio.addEventListener("durationchange", syncDuration);
    audio.addEventListener("ended", onEnded);
    audio.addEventListener("play", onPlay);
    audio.addEventListener("pause", onPause);

    return () => {
      audio.removeEventListener("timeupdate", onTimeUpdate);
      audio.removeEventListener("loadedmetadata", syncDuration);
      audio.removeEventListener("durationchange", syncDuration);
      audio.removeEventListener("ended", onEnded);
      audio.removeEventListener("play", onPlay);
      audio.removeEventListener("pause", onPause);
      audio.pause();
    };
  }, [autoAdvanceOnEnded, canGoNext, onNext, onPlayingChange, voiceSrc]);

  const togglePlay = useCallback(() => {
    const audio = audioRef.current;
    if (!audio) return;
    if (audio.paused) {
      void audio.play().catch(() => { });
      return;
    }
    audio.pause();
  }, []);

  useImperativeHandle(forwardedRef, () => ({ togglePlay }), [togglePlay]);

  const seekByClientX = useCallback((clientX: number) => {
    const audio = audioRef.current;
    const track = progressTrackRef.current;
    if (!audio || !track || !Number.isFinite(audio.duration) || audio.duration <= 0) return;
    const rect = track.getBoundingClientRect();
    if (rect.width <= 0) return;
    const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
    audio.currentTime = ratio * audio.duration;
  }, []);

  const seekWithinTrack = useCallback((delta: number) => {
    const audio = audioRef.current;
    if (!audio) return;
    const max = Number.isFinite(audio.duration) ? audio.duration : 0;
    const next = audio.currentTime + delta;
    audio.currentTime = max > 0 ? Math.min(Math.max(0, next), max) : Math.max(0, next);
  }, []);

  const handlePreviousTrack = useCallback(() => {
    if (!canGoPrevious || !onPrevious) return;
    onPrevious();
  }, [canGoPrevious, onPrevious]);

  const handleNextTrack = useCallback(() => {
    if (!canGoNext || !onNext) return;
    onNext();
  }, [canGoNext, onNext]);

  if (!voiceSrc) return null;

  const progressPercent = duration > 0 ? Math.min(100, (currentTime / duration) * 100) : 0;

  return (
    <div className={classNames("assetDetailsAudioPlayer", className)}>
      <audio ref={audioRef} className="assetDetailsAudioPlayer__engine" src={voiceSrc} preload="metadata" />
      <div className="assetDetailsAudioPlayer__controls">
        <button
          type="button"
          className="assetDetailsAudioPlayer__skipBtn assetDetailsAudioPlayer__skipBtn_rewind"
          onClick={handlePreviousTrack}
          disabled={!canGoPrevious || !onPrevious}
          aria-label={t("pages.assetDetails.audioPreviousTrack")}
        >
          <img src={new URL("/src/assets/images/ic_audio_forward.png", import.meta.url).href} alt="" />
        </button>
        <button type="button" className="assetDetailsAudioPlayer__playBtn" onClick={togglePlay} aria-label={isPlaying ? t("pages.assetDetails.audioPause") : t("pages.assetDetails.audioPlay")}>
          {isPlaying ? <img src={new URL("/src/assets/images/ic_pause_gray.png", import.meta.url).href} alt="" /> : <img src={new URL("/src/assets/images/ic_play_gray.png", import.meta.url).href} alt="" />}
        </button>
        <button
          type="button"
          className="assetDetailsAudioPlayer__skipBtn assetDetailsAudioPlayer__skipBtn_forward"
          onClick={handleNextTrack}
          disabled={!canGoNext || !onNext}
          aria-label={t("pages.assetDetails.audioNextTrack")}
        >
          <img src={new URL("/src/assets/images/ic_audio_forward.png", import.meta.url).href} alt="" />
        </button>
      </div>
      <div className="assetDetailsAudioPlayer__progressRow">
        <span className="assetDetailsAudioPlayer__time" aria-hidden>
          {formatAudioTime(currentTime)}
        </span>
        <div
          ref={progressTrackRef}
          className="assetDetailsAudioPlayer__track"
          role="slider"
          aria-label={t("pages.assetDetails.audioProgress")}
          aria-valuemin={0}
          aria-valuemax={Math.floor(duration)}
          aria-valuenow={Math.floor(currentTime)}
          tabIndex={0}
          onClick={(event) => seekByClientX(event.clientX)}
          onKeyDown={(event) => {
            if (event.key === "ArrowLeft") {
              event.preventDefault();
              seekWithinTrack(-5);
            }
            if (event.key === "ArrowRight") {
              event.preventDefault();
              seekWithinTrack(5);
            }
          }}
        >
          <div className="assetDetailsAudioPlayer__trackFill" style={{ width: `${progressPercent}%` }} />
        </div>
        <span className="assetDetailsAudioPlayer__time" aria-hidden>
          {formatAudioTime(duration)}
        </span>
      </div>
    </div>
  );
});
