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

interface UseVoiceActivityOptions {
  threshold?: number; // Порог громкости (0-100)
  smoothingTimeConstant?: number; // Сглаживание (0-1)
  fftSize?: number; // Размер FFT для анализа
  debounceTime?: number; // Время задержки выключения индикатора (ms)
}

/**
 * Хук для определения голосовой активности в MediaStream
 * @param stream - MediaStream для анализа
 * @param options - Опции для настройки детекции
 * @returns объект с isSpeaking и audioLevel
 */
export function useVoiceActivity(
  stream: MediaStream | null | undefined,
  options: UseVoiceActivityOptions = {}
): { isSpeaking: boolean; audioLevel: number } {
  const {
    threshold = 6, // Низкий порог для непрерывной речи (ловит тихие паузы между словами)
    smoothingTimeConstant = 0.8, // Высокое сглаживание для стабильности
    fftSize = 2048, // Больший размер для лучшей точности голоса
    debounceTime = 1000, // 1 секунда задержки выключения
  } = options;

  const [isSpeaking, setIsSpeaking] = useState(false);
  const [audioLevel, setAudioLevel] = useState(0);
  const audioContextRef = useRef<AudioContext | null>(null);
  const analyserRef = useRef<AnalyserNode | null>(null);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);
  const lastSpeakingTimeRef = useRef<number>(0);
  const speakingTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  useEffect(() => {
    if (!stream) {
      setIsSpeaking(false);
      setAudioLevel(0);
      return;
    }

    const audioTracks = stream.getAudioTracks();
    if (audioTracks.length === 0) {
      setIsSpeaking(false);
      setAudioLevel(0);
      return;
    }

    // Проверяем, что аудио трек активен
    const audioTrack = audioTracks[0];
    if (!audioTrack.enabled) {
      setIsSpeaking(false);
      setAudioLevel(0);
      return;
    }

    try {
      // Создаем AudioContext
      const audioContext = new AudioContext();
      audioContextRef.current = audioContext;

      // Создаем источник из MediaStream
      const source = audioContext.createMediaStreamSource(stream);

      // Создаем анализатор
      const analyser = audioContext.createAnalyser();
      analyser.fftSize = fftSize;
      analyser.smoothingTimeConstant = smoothingTimeConstant;
      analyserRef.current = analyser;

      // Подключаем источник к анализатору
      source.connect(analyser);

      // Буфер для данных
      const dataArray = new Uint8Array(analyser.frequencyBinCount);

      // Счетчик для логирования (не логируем каждый кадр)
      let frameCount = 0;

      // Функция для проверки активности
      const checkVoiceActivity = () => {
        if (!analyserRef.current) return;

        // Получаем waveform (временные данные)
        analyser.getByteTimeDomainData(dataArray);

        // Вычисляем RMS (Root Mean Square) - эффективную громкость
        // dataArray содержит значения от 0 до 255, где 128 = тишина
        let sumSquares = 0;
        for (let i = 0; i < dataArray.length; i++) {
          const normalized = (dataArray[i] - 128) / 128; // Нормализуем к диапазону -1 до 1
          sumSquares += normalized * normalized;
        }
        const rms = Math.sqrt(sumSquares / dataArray.length);

        // Преобразуем RMS в проценты (калибровка под Chrome)
        // RMS обычно в диапазоне 0.0-0.3 (тишина-громкая речь)
        // Используем нелинейную кривую для лучшего соответствия Chrome
        const audioLevel = Math.min(100, Math.pow(rms * 100, 1.2));

        // Обновляем уровень громкости постоянно
        setAudioLevel(audioLevel);

        // Проверяем, превышен ли порог
        const isActive = audioLevel > threshold;

        if (isActive) {
          // Если человек говорит сейчас - обновляем время и включаем индикатор
          lastSpeakingTimeRef.current = Date.now();
          setIsSpeaking(true);

          // Отменяем предыдущий таймер выключения (если был)
          if (speakingTimeoutRef.current) {
            clearTimeout(speakingTimeoutRef.current);
            speakingTimeoutRef.current = null;
          }
        } else {
          // Если сейчас тишина, проверяем прошло ли debounceTime с последней активности
          const timeSinceLastSpeaking =
            Date.now() - lastSpeakingTimeRef.current;

          if (timeSinceLastSpeaking >= debounceTime) {
            // Прошло достаточно времени - выключаем индикатор
            setIsSpeaking(false);
          } else if (!speakingTimeoutRef.current) {
            // Ставим таймер на выключение через оставшееся время
            const remainingTime = debounceTime - timeSinceLastSpeaking;
            speakingTimeoutRef.current = setTimeout(() => {
              setIsSpeaking(false);
              speakingTimeoutRef.current = null;
            }, remainingTime);
          }
        }

        // Логируем каждые 180 вызовов (~3 секунды при частоте 60 Hz) - снижено для меньшего шума
        frameCount++;
        if (frameCount % 180 === 0) {
          console.log(
            `[VoiceActivity] Level: ${audioLevel.toFixed(
              1
            )}% | RMS: ${rms.toFixed(
              4
            )} | Threshold: ${threshold}% | Speaking: ${
              isActive ? "🟢 YES" : "⚪ NO"
            }`
          );
        }
      };

      // Запускаем проверку с интервалом ~16ms (приблизительно 60 FPS)
      // setInterval работает стабильно даже когда окно неактивно
      intervalRef.current = setInterval(checkVoiceActivity, 16);

      console.log(
        `[useVoiceActivity] Started voice activity detection - Threshold: ${threshold}, FFT: ${fftSize}, Smoothing: ${smoothingTimeConstant}, Debounce: ${debounceTime}ms`
      );
    } catch (error) {
      console.error(
        "[useVoiceActivity] Error setting up voice detection:",
        error
      );
      setIsSpeaking(false);
      setAudioLevel(0);
    }

    // Cleanup
    return () => {
      if (intervalRef.current !== null) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }

      if (speakingTimeoutRef.current !== null) {
        clearTimeout(speakingTimeoutRef.current);
        speakingTimeoutRef.current = null;
      }

      if (analyserRef.current) {
        analyserRef.current.disconnect();
        analyserRef.current = null;
      }

      if (audioContextRef.current) {
        audioContextRef.current.close();
        audioContextRef.current = null;
      }

      setIsSpeaking(false);
      setAudioLevel(0);
      console.log("[useVoiceActivity] Cleaned up voice activity detection");
    };
  }, [stream, threshold, smoothingTimeConstant, fftSize, debounceTime]);

  return { isSpeaking, audioLevel };
}
