/**
 * AudioPlayer Component
 * Inline audio player for TTS content with play/pause, progress,
 * speed control, download, and duration display.
 *
 * Follows PDA-friendly design: no aggressive colors, calm interface.
 */

import { useState, useRef, useEffect, useCallback } from "react";
import type { ReactElement } from "react";

/** Playback speed options */
const SPEED_OPTIONS = [1, 1.5, 2, 0.5] as const;

export interface AudioPlayerProps {
  /** URL of the audio to play (blob URL or HTTP URL). If null, nothing renders. */
  src: string | null;
  /** Whether to auto-play when src changes */
  autoPlay?: boolean;
  /** Callback when play state changes */
  onPlayStateChange?: (isPlaying: boolean) => void;
  /** Optional className for the container */
  className?: string;
}

/**
 * Format seconds into M:SS display
 */
function formatTime(seconds: number): string {
  if (!isFinite(seconds) || seconds < 0) return "0:00";
  const mins = Math.floor(seconds / 60);
  const secs = Math.floor(seconds % 60);
  return `${String(mins)}:${String(secs).padStart(2, "0")}`;
}

/**
 * AudioPlayer displays an inline audio player with controls for
 * play/pause, progress tracking, speed adjustment, and download.
 */
export function AudioPlayer({
  src,
  autoPlay = false,
  onPlayStateChange,
  className = "",
}: AudioPlayerProps): ReactElement | null {
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [speedIndex, setSpeedIndex] = useState(0);

  const audioRef = useRef<HTMLAudioElement | null>(null);

  /**
   * Set up audio element when src changes
   */
  useEffect((): (() => void) | undefined => {
    if (!src) return undefined;

    const audio = new Audio(src);
    audioRef.current = audio;

    const onLoadedMetadata = (): void => {
      if (isFinite(audio.duration)) {
        setDuration(audio.duration);
      }
    };

    const onTimeUpdate = (): void => {
      setCurrentTime(audio.currentTime);
    };

    const onEnded = (): void => {
      setIsPlaying(false);
      setCurrentTime(0);
      onPlayStateChange?.(false);
    };

    audio.addEventListener("loadedmetadata", onLoadedMetadata);
    audio.addEventListener("timeupdate", onTimeUpdate);
    audio.addEventListener("ended", onEnded);

    if (autoPlay) {
      void audio.play().then(() => {
        setIsPlaying(true);
        onPlayStateChange?.(true);
      });
    }

    return (): void => {
      audio.pause();
      audio.removeEventListener("loadedmetadata", onLoadedMetadata);
      audio.removeEventListener("timeupdate", onTimeUpdate);
      audio.removeEventListener("ended", onEnded);
      audioRef.current = null;
    };
  }, [src, autoPlay, onPlayStateChange]);

  /**
   * Toggle play/pause
   */
  const togglePlayPause = useCallback(async (): Promise<void> => {
    const audio = audioRef.current;
    if (!audio) return;

    if (isPlaying) {
      audio.pause();
      setIsPlaying(false);
      onPlayStateChange?.(false);
    } else {
      await audio.play();
      setIsPlaying(true);
      onPlayStateChange?.(true);
    }
  }, [isPlaying, onPlayStateChange]);

  /**
   * Cycle through speed options
   */
  const cycleSpeed = useCallback((): void => {
    const nextIndex = (speedIndex + 1) % SPEED_OPTIONS.length;
    setSpeedIndex(nextIndex);

    const audio = audioRef.current;
    if (audio) {
      audio.playbackRate = SPEED_OPTIONS[nextIndex] ?? 1;
    }
  }, [speedIndex]);

  /**
   * Handle progress bar click for seeking
   */
  const handleProgressClick = useCallback(
    (event: React.MouseEvent<HTMLDivElement>): void => {
      const audio = audioRef.current;
      if (!audio || !duration) return;

      const rect = event.currentTarget.getBoundingClientRect();
      const clickX = event.clientX - rect.left;
      const fraction = clickX / rect.width;
      audio.currentTime = fraction * duration;
      setCurrentTime(audio.currentTime);
    },
    [duration]
  );

  /**
   * Handle download
   */
  const handleDownload = useCallback((): void => {
    if (!src) return;

    const link = document.createElement("a");
    link.href = src;
    link.download = "speech-audio.mp3";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }, [src]);

  // Don't render if no source
  if (!src) return null;

  const progress = duration > 0 ? (currentTime / duration) * 100 : 0;
  const currentSpeed = SPEED_OPTIONS[speedIndex] ?? 1;

  return (
    <div
      role="region"
      aria-label="Audio player"
      className={`flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-3 py-2 ${className}`}
    >
      {/* Play/Pause Button */}
      <button
        type="button"
        onClick={() => void togglePlayPause()}
        aria-label={isPlaying ? "Pause audio" : "Play audio"}
        className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-500 text-white transition-colors hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-300"
      >
        {isPlaying ? (
          <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
            <rect x="6" y="4" width="4" height="16" rx="1" />
            <rect x="14" y="4" width="4" height="16" rx="1" />
          </svg>
        ) : (
          <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
            <polygon points="6,4 20,12 6,20" />
          </svg>
        )}
      </button>

      {/* Time Display */}
      <span className="min-w-[3.5rem] text-xs text-gray-500 tabular-nums">
        {formatTime(currentTime)}
        {duration > 0 && <span className="text-gray-400"> / {formatTime(duration)}</span>}
      </span>

      {/* Progress Bar */}
      <div
        role="progressbar"
        aria-label="Audio progress"
        aria-valuenow={Math.round(progress)}
        aria-valuemin={0}
        aria-valuemax={100}
        className="relative h-1.5 flex-1 cursor-pointer rounded-full bg-gray-200"
        onClick={handleProgressClick}
      >
        <div
          className="absolute left-0 top-0 h-full rounded-full bg-blue-400 transition-all"
          style={{ width: `${String(Math.min(progress, 100))}%` }}
        />
      </div>

      {/* Speed Control */}
      <button
        type="button"
        onClick={cycleSpeed}
        aria-label="Playback speed"
        className="min-w-[2.5rem] rounded px-1.5 py-0.5 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-300"
      >
        {String(currentSpeed)}x
      </button>

      {/* Download Button */}
      <button
        type="button"
        onClick={handleDownload}
        aria-label="Download audio"
        className="flex h-7 w-7 shrink-0 items-center justify-center rounded text-gray-500 transition-colors hover:bg-gray-200 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-300"
      >
        <svg
          width="14"
          height="14"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
          aria-hidden="true"
        >
          <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" />
          <polyline points="7 10 12 15 17 10" />
          <line x1="12" y1="15" x2="12" y2="3" />
        </svg>
      </button>
    </div>
  );
}

export default AudioPlayer;
