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

export type RecordingState = "idle" | "recording" | "recorded";

interface UseAudioRecorderOptions {
  audioContext: AudioContext | null;
}

interface UseAudioRecorderReturn {
  // State
  recordingState: RecordingState;
  recordedAudioUrl: string | null;

  // Audio nodes
  audioDestination: MediaStreamAudioDestinationNode | null;

  // Controls
  startRecording: () => void;
  stopRecording: () => void;
  clearRecording: () => void;

  // For connecting audio nodes during playback
  connectToRecording: (node: AudioNode) => void;
}

/**
 * Hook for recording audio output from Web Audio API.
 *
 * This records the actual audio as the user hears it, not events.
 * Perfect for capturing musical performances, synth tweaks, etc.
 *
 * Usage:
 * 1. Pass in your AudioContext
 * 2. When creating sounds, connect nodes to audioDestination if recording
 * 3. Use startRecording/stopRecording to control recording
 * 4. Use recordedAudioUrl to play back the recording
 *
 * Example:
 * ```
 * const { recordingState, audioDestination, startRecording, recordedAudioUrl } = useAudioRecorder({ audioContext });
 *
 * // When playing a sound:
 * const osc = audioContext.createOscillator();
 * osc.connect(audioContext.destination); // Always connect to speakers
 * if (audioDestination) {
 *   osc.connect(audioDestination); // Also connect to recorder when available
 * }
 * ```
 */
export function useAudioRecorder({
  audioContext,
}: UseAudioRecorderOptions): UseAudioRecorderReturn {
  const [recordingState, setRecordingState] = useState<RecordingState>("idle");
  const [recordedAudioUrl, setRecordedAudioUrl] = useState<string | null>(null);

  const audioDestinationRef = useRef<MediaStreamAudioDestinationNode | null>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const audioChunksRef = useRef<Blob[]>([]);
  const recordingStartTimeRef = useRef<number>(0);

  // Create audio destination when context is available
  useEffect(() => {
    if (audioContext && !audioDestinationRef.current) {
      const dest = audioContext.createMediaStreamDestination();
      audioDestinationRef.current = dest;

      // Log audio track settings for debugging
      const tracks = dest.stream.getAudioTracks();
      if (tracks.length > 0) {
        const settings = tracks[0].getSettings();
        console.log('MediaStream audio track settings:', {
          sampleRate: settings.sampleRate,
          channelCount: settings.channelCount,
          audioContextSampleRate: audioContext.sampleRate
        });
      }
    }
  }, [audioContext]);

  // Cleanup audio URL on unmount
  useEffect(() => {
    return () => {
      if (recordedAudioUrl) {
        URL.revokeObjectURL(recordedAudioUrl);
      }
    };
  }, [recordedAudioUrl]);

  const startRecording = useCallback(() => {
    if (!audioDestinationRef.current || !audioContext) {
      console.error("Audio destination not ready");
      return;
    }

    // Clear previous recording
    if (recordedAudioUrl) {
      URL.revokeObjectURL(recordedAudioUrl);
      setRecordedAudioUrl(null);
    }

    // Start audio stream recording
    audioChunksRef.current = [];

    try {
      // Try to match the AudioContext sample rate
      const sampleRate = audioContext.sampleRate;
      console.log(`Starting recording - AudioContext sample rate: ${sampleRate}Hz`);

      // Try different codec options to get best quality and timing
      // Opus at 48kHz is the most common and reliable
      let options: MediaRecorderOptions = {
        mimeType: 'audio/webm;codecs=opus',
        audioBitsPerSecond: 128000 // Explicit bitrate for consistency
      };

      if (!MediaRecorder.isTypeSupported(options.mimeType!)) {
        console.warn('opus codec not supported, trying webm with default codec');
        options = {
          mimeType: 'audio/webm',
          audioBitsPerSecond: 128000
        };
      }

      if (!MediaRecorder.isTypeSupported(options.mimeType!)) {
        console.warn('webm not supported, using default mime type');
        options = { audioBitsPerSecond: 128000 };
      }

      const mediaRecorder = new MediaRecorder(audioDestinationRef.current.stream, options);
      console.log(`MediaRecorder created with mimeType: ${mediaRecorder.mimeType}`);

      mediaRecorder.ondataavailable = (event) => {
        if (event.data && event.data.size > 0) {
          audioChunksRef.current.push(event.data);
        }
      };

      mediaRecorder.onstop = () => {
        if (audioChunksRef.current.length > 0) {
          const actualDuration = Date.now() - recordingStartTimeRef.current;
          const blob = new Blob(audioChunksRef.current, { type: "audio/webm" });
          const url = URL.createObjectURL(blob);
          console.log(`Recording complete: ${(blob.size / 1024).toFixed(2)}KB, type: ${blob.type}, actual duration: ${(actualDuration / 1000).toFixed(2)}s`);

          // Create a temporary audio element to check the recorded duration
          const tempAudio = new Audio(url);
          tempAudio.addEventListener('loadedmetadata', () => {
            console.log(`Recorded audio duration: ${tempAudio.duration.toFixed(2)}s (expected: ${(actualDuration / 1000).toFixed(2)}s)`);
            if (Math.abs(tempAudio.duration - actualDuration / 1000) > 0.1) {
              console.warn(`⚠️ Timing mismatch detected! Recorded: ${tempAudio.duration.toFixed(2)}s, Expected: ${(actualDuration / 1000).toFixed(2)}s`);
            }
          });

          setRecordedAudioUrl(url);
        }
      };

      mediaRecorder.onerror = (event) => {
        console.error("MediaRecorder error:", event);
      };

      mediaRecorder.onstart = () => {
        recordingStartTimeRef.current = Date.now();
        console.log(`Recording started with ${mediaRecorder.mimeType} at ${mediaRecorder.audioBitsPerSecond || 'auto'} bps`);
      };

      mediaRecorderRef.current = mediaRecorder;
      // Start recording without timeslice to avoid chunking issues that can affect timing
      mediaRecorder.start();
      setRecordingState("recording");
    } catch (error) {
      console.error("Failed to start audio recording:", error);
    }
  }, [recordedAudioUrl, audioContext]);

  const stopRecording = useCallback(() => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state === "recording") {
      mediaRecorderRef.current.stop();
    }
    setRecordingState("recorded");
  }, []);

  const clearRecording = useCallback(() => {
    if (recordedAudioUrl) {
      URL.revokeObjectURL(recordedAudioUrl);
      setRecordedAudioUrl(null);
    }
    setRecordingState("idle");
  }, [recordedAudioUrl]);

  const connectToRecording = useCallback((node: AudioNode) => {
    if (audioDestinationRef.current) {
      node.connect(audioDestinationRef.current);
    }
  }, []);

  return {
    recordingState,
    recordedAudioUrl,
    audioDestination: audioDestinationRef.current,
    startRecording,
    stopRecording,
    clearRecording,
    connectToRecording,
  };
}
