/**
 * useAudioQueue — Playlist-style audio playback queue.
 *
 * When multiple audio clips arrive (e.g. TTS chunks from the agent), they are
 * queued and played sequentially. The next clip only starts once the current
 * one finishes (or is skipped). Individual clips can still be paused/resumed.
 */

import { useCallback, useRef, useState } from 'react';

export interface AudioQueueItem {
  id: string;
  url: string;
  language?: string;
  charCount?: number;
}

export interface AudioQueueState {
  currentId: string | null;
  isPlaying: boolean;
  isPaused: boolean;
  queueLength: number;
}

export interface AudioQueueApi {
  state: AudioQueueState;
  enqueue: (item: AudioQueueItem) => void;
  pause: () => void;
  resume: () => void;
  skip: () => void;
  stopAll: () => void;
  isItemActive: (id: string) => boolean;
  isItemQueued: (id: string) => boolean;
  getProgress: () => number;
  getDuration: () => number;
}

export function useAudioQueue(): AudioQueueApi {
  const queueRef = useRef<AudioQueueItem[]>([]);
  const audioRef = useRef<HTMLAudioElement | null>(null);
  const currentIdRef = useRef<string | null>(null);
  const playingRef = useRef(false);

  const [state, setState] = useState<AudioQueueState>({
    currentId: null,
    isPlaying: false,
    isPaused: false,
    queueLength: 0,
  });

  const _updateState = useCallback((patch: Partial<AudioQueueState>) => {
    setState(prev => ({ ...prev, ...patch }));
  }, []);

  const _playNext = useCallback(() => {
    if (playingRef.current) return;

    const next = queueRef.current.shift();
    if (!next) {
      currentIdRef.current = null;
      _updateState({ currentId: null, isPlaying: false, isPaused: false, queueLength: 0 });
      return;
    }

    playingRef.current = true;
    currentIdRef.current = next.id;
    _updateState({
      currentId: next.id,
      isPlaying: true,
      isPaused: false,
      queueLength: queueRef.current.length,
    });

    const audio = new Audio(next.url);
    audioRef.current = audio;

    audio.addEventListener('ended', () => {
      audioRef.current = null;
      playingRef.current = false;
      currentIdRef.current = null;
      _updateState({
        currentId: null,
        isPlaying: false,
        isPaused: false,
        queueLength: queueRef.current.length,
      });
      _playNext();
    });

    audio.addEventListener('error', () => {
      audioRef.current = null;
      playingRef.current = false;
      currentIdRef.current = null;
      _playNext();
    });

    audio.play().catch(() => {
      audioRef.current = null;
      playingRef.current = false;
      currentIdRef.current = null;
      _playNext();
    });
  }, [_updateState]);

  const enqueue = useCallback((item: AudioQueueItem) => {
    queueRef.current.push(item);
    _updateState({ queueLength: queueRef.current.length });
    if (!playingRef.current) {
      _playNext();
    }
  }, [_playNext, _updateState]);

  const pause = useCallback(() => {
    if (audioRef.current && !audioRef.current.paused) {
      audioRef.current.pause();
      _updateState({ isPaused: true });
    }
  }, [_updateState]);

  const resume = useCallback(() => {
    if (audioRef.current && audioRef.current.paused) {
      audioRef.current.play().catch(() => {});
      _updateState({ isPaused: false });
    }
  }, [_updateState]);

  const skip = useCallback(() => {
    if (audioRef.current) {
      audioRef.current.pause();
      audioRef.current.removeAttribute('src');
      audioRef.current = null;
    }
    playingRef.current = false;
    currentIdRef.current = null;
    _playNext();
  }, [_playNext]);

  const stopAll = useCallback(() => {
    queueRef.current = [];
    if (audioRef.current) {
      audioRef.current.pause();
      audioRef.current.removeAttribute('src');
      audioRef.current = null;
    }
    playingRef.current = false;
    currentIdRef.current = null;
    _updateState({ currentId: null, isPlaying: false, isPaused: false, queueLength: 0 });
  }, [_updateState]);

  const isItemActive = useCallback((id: string) => currentIdRef.current === id, []);
  const isItemQueued = useCallback((id: string) => queueRef.current.some(q => q.id === id), []);

  const getProgress = useCallback(() => {
    const a = audioRef.current;
    if (!a || !a.duration) return 0;
    return a.currentTime / a.duration;
  }, []);

  const getDuration = useCallback(() => {
    return audioRef.current?.duration ?? 0;
  }, []);

  return {
    state,
    enqueue,
    pause,
    resume,
    skip,
    stopAll,
    isItemActive,
    isItemQueued,
    getProgress,
    getDuration,
  };
}
