'use client';

/**
 * Voice Notes Component
 * 
 * Record audio notes for deliveries with:
 * - Recording indicator
 * - Playback
 * - Duration display
 * - IndexedDB storage for offline
 */

import { useState, useRef, useCallback, useEffect } from 'react';
import { Mic, MicOff, Play, Pause, Trash2, Square, Loader2 } from 'lucide-react';

interface VoiceNoteProps {
  onRecordingComplete: (audioBlob: Blob, duration: number) => void;
  onTranscript?: (text: string) => void;
  existingAudioUrl?: string;
  maxDuration?: number; // seconds
  className?: string;
  enableTranscription?: boolean;
}

export function VoiceNote({ 
  onRecordingComplete, 
  onTranscript,
  existingAudioUrl,
  maxDuration = 120, // 2 minutes default
  className = '',
  enableTranscription = true,
}: VoiceNoteProps) {
  const [isRecording, setIsRecording] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);
  const [duration, setDuration] = useState(0);
  const [recordedUrl, setRecordedUrl] = useState<string | null>(existingAudioUrl || null);
  const [recordedBlob, setRecordedBlob] = useState<Blob | null>(null);
  const [permissionDenied, setPermissionDenied] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [transcript, setTranscript] = useState('');
  const [isTranscribing, setIsTranscribing] = useState(false);

  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const audioChunksRef = useRef<Blob[]>([]);
  const audioRef = useRef<HTMLAudioElement | null>(null);
  const timerRef = useRef<NodeJS.Timeout | null>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const speechRecognitionRef = useRef<any>(null);

  // Format duration as MM:SS
  const formatDuration = (seconds: number): string => {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  };

  const startTranscription = useCallback(() => {
    if (!enableTranscription) return;
    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    if (!SpeechRecognition) return;

    const recognition = new SpeechRecognition();
    recognition.lang = 'en-US';
    recognition.continuous = true;
    recognition.interimResults = true;
    recognition.onresult = (event: any) => {
      let finalText = '';
      let interimText = '';

      for (let i = event.resultIndex; i < event.results.length; i++) {
        const result = event.results[i];
        if (result.isFinal) {
          finalText += result[0].transcript;
        } else {
          interimText += result[0].transcript;
        }
      }

      const merged = `${finalText} ${interimText}`.trim();
      if (merged) {
        setTranscript(merged);
        onTranscript?.(merged);
      }
    };
    recognition.onerror = () => setIsTranscribing(false);
    recognition.onend = () => setIsTranscribing(false);
    recognition.start();

    speechRecognitionRef.current = recognition;
    setIsTranscribing(true);
  }, [enableTranscription, onTranscript]);

  const stopTranscription = useCallback(() => {
    if (speechRecognitionRef.current) {
      try {
        speechRecognitionRef.current.stop();
      } catch {
        // ignore
      }
      speechRecognitionRef.current = null;
    }
    setIsTranscribing(false);
  }, []);

  // Start recording
  const startRecording = useCallback(async () => {
    try {
      setIsLoading(true);
      const stream = await navigator.mediaDevices.getUserMedia({ 
        audio: {
          echoCancellation: true,
          noiseSuppression: true,
          sampleRate: 44100,
        } 
      });
      
      streamRef.current = stream;
      const mediaRecorder = new MediaRecorder(stream, {
        mimeType: MediaRecorder.isTypeSupported('audio/webm') ? 'audio/webm' : 'audio/mp4'
      });
      
      mediaRecorderRef.current = mediaRecorder;
      audioChunksRef.current = [];

      mediaRecorder.ondataavailable = (event) => {
        if (event.data.size > 0) {
          audioChunksRef.current.push(event.data);
        }
      };

      mediaRecorder.onstop = () => {
        const audioBlob = new Blob(audioChunksRef.current, { 
          type: mediaRecorder.mimeType 
        });
        const url = URL.createObjectURL(audioBlob);
        setRecordedUrl(url);
        setRecordedBlob(audioBlob);
        onRecordingComplete(audioBlob, duration);
        
        // Stop all tracks
        stream.getTracks().forEach(track => track.stop());
      };

      mediaRecorder.start(100); // Collect data every 100ms
      setIsRecording(true);
      setDuration(0);
      setIsLoading(false);
      startTranscription();

      // Start timer
      timerRef.current = setInterval(() => {
        setDuration(prev => {
          if (prev >= maxDuration) {
            stopRecording();
            return prev;
          }
          return prev + 1;
        });
      }, 1000);

      // Haptic feedback
      if (navigator.vibrate) {
        navigator.vibrate(50);
      }
    } catch (error: any) {
      console.error('Failed to start recording:', error);
      setIsLoading(false);
      if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
        setPermissionDenied(true);
      }
    }
  }, [maxDuration, duration, onRecordingComplete, startTranscription]);

  // Stop recording
  const stopRecording = useCallback(() => {
    if (mediaRecorderRef.current && isRecording) {
      mediaRecorderRef.current.stop();
      setIsRecording(false);
      setIsPaused(false);
      stopTranscription();
      
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }

      // Haptic feedback
      if (navigator.vibrate) {
        navigator.vibrate([50, 30, 50]);
      }
    }
  }, [isRecording, stopTranscription]);

  // Pause/Resume recording
  const togglePause = useCallback(() => {
    if (mediaRecorderRef.current) {
      if (isPaused) {
        mediaRecorderRef.current.resume();
        timerRef.current = setInterval(() => {
          setDuration(prev => prev + 1);
        }, 1000);
      } else {
        mediaRecorderRef.current.pause();
        if (timerRef.current) {
          clearInterval(timerRef.current);
        }
      }
      setIsPaused(!isPaused);
    }
  }, [isPaused]);

  // Play recorded audio
  const playAudio = useCallback(() => {
    if (recordedUrl && audioRef.current) {
      audioRef.current.play();
      setIsPlaying(true);
    }
  }, [recordedUrl]);

  // Pause playback
  const pauseAudio = useCallback(() => {
    if (audioRef.current) {
      audioRef.current.pause();
      setIsPlaying(false);
    }
  }, []);

  // Delete recording
  const deleteRecording = useCallback(() => {
    if (recordedUrl) {
      URL.revokeObjectURL(recordedUrl);
    }
    setRecordedUrl(null);
    setRecordedBlob(null);
    setDuration(0);
    setIsPlaying(false);
    setTranscript('');
    onTranscript?.('');
    stopTranscription();

    // Haptic feedback
    if (navigator.vibrate) {
      navigator.vibrate(100);
    }
  }, [recordedUrl, onTranscript, stopTranscription]);

  // Handle audio ended
  useEffect(() => {
    if (audioRef.current) {
      audioRef.current.onended = () => setIsPlaying(false);
    }
  }, [recordedUrl]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (timerRef.current) {
        clearInterval(timerRef.current);
      }
      if (recordedUrl && !existingAudioUrl) {
        URL.revokeObjectURL(recordedUrl);
      }
      if (streamRef.current) {
        streamRef.current.getTracks().forEach(track => track.stop());
      }
      stopTranscription();
    };
  }, [recordedUrl, existingAudioUrl, stopTranscription]);

  if (permissionDenied) {
    return (
      <div className={`flex items-center gap-2 rounded-xl bg-red-50 p-3 text-sm text-red-600 ${className}`}>
        <MicOff className="h-5 w-5" />
        <span>Microphone access denied. Please enable it in your browser settings.</span>
      </div>
    );
  }

  return (
    <div className={`rounded-xl border border-slate-200 bg-slate-50 p-3 ${className}`}>
      <div className="flex items-center gap-3">
        {/* Recording/Playback controls */}
        {!recordedUrl ? (
          // Recording mode
          <>
            {isRecording ? (
              <div className="flex items-center gap-2">
                <button
                  onClick={stopRecording}
                  className="flex h-12 w-12 items-center justify-center rounded-full bg-red-500 text-white shadow-lg hover:bg-red-600 transition-all animate-pulse"
                  title="Stop recording"
                >
                  <Square className="h-5 w-5" fill="currentColor" />
                </button>
                <button
                  onClick={togglePause}
                  className="flex h-10 w-10 items-center justify-center rounded-full bg-slate-200 text-slate-700 hover:bg-slate-300 transition-all"
                  title={isPaused ? 'Resume' : 'Pause'}
                >
                  {isPaused ? <Play className="h-4 w-4" /> : <Pause className="h-4 w-4" />}
                </button>
              </div>
            ) : (
              <button
                onClick={startRecording}
                disabled={isLoading}
                className="flex h-12 w-12 items-center justify-center rounded-full bg-emerald-500 text-white shadow-lg hover:bg-emerald-600 transition-all disabled:opacity-50"
                title="Start recording"
              >
                {isLoading ? (
                  <Loader2 className="h-5 w-5 animate-spin" />
                ) : (
                  <Mic className="h-5 w-5" />
                )}
              </button>
            )}

            <div className="flex-1">
              <div className="text-sm font-medium text-slate-700">
                {isRecording ? (isPaused ? 'Paused' : 'Recording...') : 'Tap to record voice note'}
              </div>
              <div className="text-xs text-slate-500">
                {isRecording ? (
                  <span className={isPaused ? '' : 'text-red-500'}>
                    {formatDuration(duration)} / {formatDuration(maxDuration)}
                  </span>
                ) : (
                  `Max ${formatDuration(maxDuration)}`
                )}
              </div>
            </div>

            {/* Recording indicator */}
            {isRecording && !isPaused && (
              <div className="flex items-center gap-1">
                <div className="h-2 w-2 rounded-full bg-red-500 animate-pulse" />
                <span className="text-xs text-red-500 font-medium">REC</span>
              </div>
            )}
          </>
        ) : (
          // Playback mode
          <>
            <button
              onClick={isPlaying ? pauseAudio : playAudio}
              className="flex h-12 w-12 items-center justify-center rounded-full bg-emerald-500 text-white shadow-lg hover:bg-emerald-600 transition-all"
              title={isPlaying ? 'Pause' : 'Play'}
            >
              {isPlaying ? <Pause className="h-5 w-5" /> : <Play className="h-5 w-5 ml-0.5" />}
            </button>

            <div className="flex-1">
              <div className="text-sm font-medium text-slate-700">Voice note recorded</div>
              <div className="text-xs text-slate-500">{formatDuration(duration)}</div>
            </div>

            <button
              onClick={deleteRecording}
              className="flex h-10 w-10 items-center justify-center rounded-full bg-red-100 text-red-600 hover:bg-red-200 transition-all"
              title="Delete recording"
            >
              <Trash2 className="h-4 w-4" />
            </button>

            <audio ref={audioRef} src={recordedUrl} />
          </>
        )}
      </div>

      {/* Waveform visualization placeholder */}
      {isRecording && (
        <div className="mt-3 flex items-center justify-center gap-1 h-8">
          {Array.from({ length: 20 }).map((_, i) => (
            <div
              key={i}
              className="w-1 bg-emerald-400 rounded-full animate-pulse"
              style={{
                height: `${Math.random() * 24 + 8}px`,
                animationDelay: `${i * 50}ms`,
              }}
            />
          ))}
        </div>
      )}

      {enableTranscription && (
        <div className="mt-3 rounded-lg bg-white p-3 text-xs text-slate-700">
          <div className="mb-1 flex items-center justify-between">
            <span className="font-semibold text-slate-600">Transcript</span>
            {isTranscribing && <span className="text-[10px] text-emerald-600">Listening…</span>}
          </div>
          <div className="min-h-[40px] whitespace-pre-wrap text-slate-700">
            {transcript || 'No transcript yet'}
          </div>
        </div>
      )}
    </div>
  );
}

// Hook for voice note storage
export function useVoiceNoteStorage() {
  const saveVoiceNote = useCallback(async (
    deliveryId: string,
    audioBlob: Blob
  ): Promise<string> => {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open('gcx_fshs_voice_notes', 1);
      
      request.onerror = () => reject(request.error);
      
      request.onupgradeneeded = () => {
        const db = request.result;
        if (!db.objectStoreNames.contains('voice_notes')) {
          db.createObjectStore('voice_notes', { keyPath: 'id' });
        }
      };
      
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction('voice_notes', 'readwrite');
        const store = transaction.objectStore('voice_notes');
        
        const id = `vn_${deliveryId}_${Date.now()}`;
        store.put({ id, blob: audioBlob, createdAt: Date.now() });
        
        transaction.oncomplete = () => resolve(id);
        transaction.onerror = () => reject(transaction.error);
      };
    });
  }, []);

  const getVoiceNote = useCallback(async (id: string): Promise<Blob | null> => {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open('gcx_fshs_voice_notes', 1);
      
      request.onerror = () => reject(request.error);
      
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction('voice_notes', 'readonly');
        const store = transaction.objectStore('voice_notes');
        const getRequest = store.get(id);
        
        getRequest.onsuccess = () => {
          resolve(getRequest.result?.blob || null);
        };
        getRequest.onerror = () => reject(getRequest.error);
      };
    });
  }, []);

  const deleteVoiceNote = useCallback(async (id: string): Promise<void> => {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open('gcx_fshs_voice_notes', 1);
      
      request.onerror = () => reject(request.error);
      
      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction('voice_notes', 'readwrite');
        const store = transaction.objectStore('voice_notes');
        store.delete(id);
        
        transaction.oncomplete = () => resolve();
        transaction.onerror = () => reject(transaction.error);
      };
    });
  }, []);

  return { saveVoiceNote, getVoiceNote, deleteVoiceNote };
}
