import { useEffect, useRef, useState, useCallback } from 'react';
import { LayeredAudioEngine } from '../utils/audioEngine';
import { InstrumentLayer } from '../utils/types';

export function useAudioEngine() {
  const engineRef = useRef<LayeredAudioEngine | null>(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [isLoading, setIsLoading] = useState(false);

  // Initialize engine
  useEffect(() => {
    engineRef.current = new LayeredAudioEngine();
    
    return () => {
      if (engineRef.current) {
        engineRef.current.dispose();
      }
    };
  }, []);

  // Update current time while playing
  useEffect(() => {
    if (!isPlaying || !engineRef.current) return;

    const interval = setInterval(() => {
      if (engineRef.current) {
        setCurrentTime(engineRef.current.getCurrentTime());
      }
    }, 100); // Update every 100ms

    return () => clearInterval(interval);
  }, [isPlaying]);

  const play = useCallback(async (layers: InstrumentLayer[]) => {
    if (!engineRef.current) return;

    try {
      setIsLoading(true);
      await engineRef.current.playAll(layers);
      setIsPlaying(true);
      setDuration(engineRef.current.getDuration(layers));
    } catch (error) {
      console.error('Failed to play layers:', error);
    } finally {
      setIsLoading(false);
    }
  }, []);

  const stop = useCallback(() => {
    if (!engineRef.current) return;

    engineRef.current.stopAll();
    setIsPlaying(false);
    setCurrentTime(0);
  }, []);

  const pause = useCallback(() => {
    if (!engineRef.current) return;

    engineRef.current.pauseAll();
    setIsPlaying(false);
  }, []);

  const resume = useCallback(async (layers: InstrumentLayer[]) => {
    if (!engineRef.current) return;

    try {
      setIsLoading(true);
      await engineRef.current.resumeAll(layers);
      setIsPlaying(true);
    } catch (error) {
      console.error('Failed to resume playback:', error);
    } finally {
      setIsLoading(false);
    }
  }, []);

  const setMasterVolume = useCallback((volume: number) => {
    if (!engineRef.current) return;
    engineRef.current.setMasterVolume(volume);
  }, []);

  const setLayerVolume = useCallback((layerId: string, volume: number) => {
    if (!engineRef.current) return;
    engineRef.current.setLayerVolume(layerId, volume);
  }, []);

  const setLayerMute = useCallback((layerId: string, muted: boolean) => {
    if (!engineRef.current) return;
    engineRef.current.setLayerMute(layerId, muted);
  }, []);

  const removeLayer = useCallback((layerId: string) => {
    if (!engineRef.current) return;
    engineRef.current.removeLayer(layerId);
  }, []);

  const loadLayer = useCallback(async (layer: InstrumentLayer): Promise<InstrumentLayer | undefined> => {
    if (!engineRef.current || !layer.audioUrl) return;

    try {
      const updatedLayer = await engineRef.current.loadLayer(layer);
      return updatedLayer;
    } catch (error) {
      console.error('Failed to load layer:', error);
      return undefined;
    }
  }, []);

  const seekTo = useCallback(async (time: number, layers: InstrumentLayer[]) => {
    if (!engineRef.current) return;

    try {
      await engineRef.current.seekTo(time, layers);
      setCurrentTime(time);
    } catch (error) {
      console.error('Failed to seek:', error);
    }
  }, []);

  return {
    // State
    isPlaying,
    currentTime,
    duration,
    isLoading,
    
    // Controls
    play,
    stop,
    pause,
    resume,
    seekTo,
    
    // Volume controls
    setMasterVolume,
    setLayerVolume,
    setLayerMute,
    
    // Layer management
    removeLayer,
    loadLayer
  };
}