import { useState, useRef, useCallback, useEffect } from 'react';
import { transcribeAudio } from '@/api/voice';

/**
 * 浏览器 Speech Recognition API 的类型声明补充
 * 完整声明见 vite-env.d.ts
 */

interface UseSpeechRecognitionReturn {
  isListening: boolean;
  isSupported: boolean;
  interimText: string;
  finalText: string;
  error: string | null;
  /** 是否正在使用后端 STT 降级模式 */
  isFallbackMode: boolean;
  startListening: () => void;
  stopListening: () => void;
  resetText: () => void;
}

type RecognitionError =
  | 'no-speech'
  | 'aborted'
  | 'audio-capture'
  | 'network'
  | 'not-allowed'
  | 'service-not-allowed'
  | 'bad-grammar'
  | 'language-not-supported';

const ERROR_MESSAGES: Record<RecognitionError, string> = {
  'no-speech': '未检测到语音，请再试一次',
  'aborted': '语音输入已中止',
  'audio-capture': '无法访问麦克风设备',
  'network': '网络错误，已切换到后端语音识别',
  'not-allowed': '麦克风权限被拒绝，请在浏览器设置中允许麦克风访问',
  'service-not-allowed': '语音识别服务不可用',
  'bad-grammar': '语法配置错误',
  'language-not-supported': '当前语言不支持语音识别',
};

function getRecognitionError(error: string): string {
  return ERROR_MESSAGES[error as RecognitionError] || `语音识别错误: ${error}`;
}

export function useSpeechRecognition(): UseSpeechRecognitionReturn {
  const [isListening, setIsListening] = useState(false);
  const [interimText, setInterimText] = useState('');
  const [finalText, setFinalText] = useState('');
  const [error, setError] = useState<string | null>(null);
  const [isFallbackMode, setIsFallbackMode] = useState(false);

  const recognitionRef = useRef<SpeechRecognition | null>(null);
  const finalAccRef = useRef<string[]>([]);

  // --- 后端 STT 降级：MediaRecorder ---
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const audioChunksRef = useRef<Blob[]>([]);
  const fallbackStreamRef = useRef<MediaStream | null>(null);

  const SpeechRecognitionAPI =
    typeof window !== 'undefined'
      ? window.SpeechRecognition || window.webkitSpeechRecognition
      : undefined;

  // 只要浏览器支持 MediaRecorder 就算语音输入可用
  const isSupported =
    typeof window !== 'undefined' &&
    (SpeechRecognitionAPI != null || typeof MediaRecorder !== 'undefined');

  const resetText = useCallback(() => {
    setInterimText('');
    setFinalText('');
    finalAccRef.current = [];
  }, []);

  // 清理浏览器 STT
  const cleanupBrowserSTT = useCallback(() => {
    if (recognitionRef.current) {
      recognitionRef.current.abort();
      recognitionRef.current = null;
    }
  }, []);

  // 清理 MediaRecorder 降级
  const cleanupFallback = useCallback(() => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
      mediaRecorderRef.current.stop();
    }
    mediaRecorderRef.current = null;
    if (fallbackStreamRef.current) {
      fallbackStreamRef.current.getTracks().forEach((t) => t.stop());
      fallbackStreamRef.current = null;
    }
    audioChunksRef.current = [];
  }, []);

  const stopListening = useCallback(() => {
    cleanupBrowserSTT();
    cleanupFallback();
    setIsListening(false);
    setIsFallbackMode(false);
    setError(null);
  }, [cleanupBrowserSTT, cleanupFallback]);

  // 自动静默超时：若 3 秒内无任何结果，自动停止
  const silenceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const resetSilenceTimer = useCallback(() => {
    if (silenceTimerRef.current) {
      clearTimeout(silenceTimerRef.current);
    }
    silenceTimerRef.current = setTimeout(() => {
      stopListening();
    }, 3000);
  }, [stopListening]);

  // --- 后端 STT 降级：启动 MediaRecorder 录音 ---
  const startFallbackRecognition = useCallback(async () => {
    try {
      setIsFallbackMode(true);
      setError(null);

      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      fallbackStreamRef.current = stream;

      const mimeType = MediaRecorder.isTypeSupported('audio/webm;codecs=opus')
        ? 'audio/webm;codecs=opus'
        : MediaRecorder.isTypeSupported('audio/webm')
          ? 'audio/webm'
          : 'audio/mp4';

      const recorder = new MediaRecorder(stream, { mimeType });
      mediaRecorderRef.current = recorder;
      audioChunksRef.current = [];

      recorder.ondataavailable = (e) => {
        if (e.data.size > 0) {
          audioChunksRef.current.push(e.data);
        }
      };

      recorder.onstop = async () => {
        const audioBlob = new Blob(audioChunksRef.current, { type: recorder.mimeType });
        audioChunksRef.current = [];

        // 调用后端 STT
        const result = await transcribeAudio(audioBlob, 'zh');

        if (result.error) {
          setError(`后端语音识别失败: ${result.error}`);
          setIsListening(false);
          setIsFallbackMode(false);
          return;
        }

        if (result.data?.text) {
          setFinalText(result.data.text);
        } else {
          setError('未识别到语音内容');
        }
        setIsListening(false);
        setIsFallbackMode(false);
      };

      recorder.onerror = () => {
        setError('录音设备出错，请重试');
        setIsListening(false);
        setIsFallbackMode(false);
      };

      recorder.start();
      setIsListening(true);
      // 降级模式没有 interim results，所以超时设长一点
      if (silenceTimerRef.current) clearTimeout(silenceTimerRef.current);
      silenceTimerRef.current = setTimeout(() => {
        stopListening();
      }, 15000); // 15s 最大录音时长

    } catch (err) {
      const msg = err instanceof DOMException && err.name === 'NotAllowedError'
        ? '麦克风权限被拒绝'
        : err instanceof Error ? err.message : '无法启动录音';
      setError(msg);
      setIsFallbackMode(false);
    }
  }, [stopListening]);

  const startListening = useCallback(() => {
    // 如果已有实例则先停止
    cleanupBrowserSTT();
    cleanupFallback();

    setError(null);
    setInterimText('');
    setFinalText('');
    finalAccRef.current = [];
    setIsFallbackMode(false);

    if (!SpeechRecognitionAPI) {
      // 浏览器不支持 SpeechRecognition，直接使用后端 STT
      startFallbackRecognition();
      return;
    }

    const recognition = new SpeechRecognitionAPI();
    recognition.continuous = true;
    recognition.interimResults = true;
    recognition.lang = 'zh-CN';

    recognition.onresult = (event: SpeechRecognitionEvent) => {
      resetSilenceTimer();

      let newInterim = '';

      for (let i = event.resultIndex; i < event.results.length; i++) {
        const result = event.results[i];
        if (result.isFinal) {
          finalAccRef.current.push(result[0].transcript);
        } else {
          newInterim += result[0].transcript;
        }
      }

      setInterimText(newInterim);
      setFinalText(finalAccRef.current.join(''));
    };

    recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
      if (event.error === 'network') {
        // 网络错误 → 自动降级到后端 STT
        cleanupBrowserSTT();
        setError('浏览器语音识别网络不可达，正在切换到后端识别...');
        startFallbackRecognition();
        return;
      }

      const message = getRecognitionError(event.error);
      setError(message);

      if (event.error === 'no-speech') {
        // 无语音不算致命错误，可以继续
      } else {
        setIsListening(false);
        recognitionRef.current = null;
      }
    };

    recognition.onend = () => {
      setIsListening(false);
      recognitionRef.current = null;
      if (silenceTimerRef.current) {
        clearTimeout(silenceTimerRef.current);
        silenceTimerRef.current = null;
      }

      // onend 时把已累积的 final 结果合并
      if (finalAccRef.current.length > 0) {
        setFinalText(finalAccRef.current.join(''));
        setInterimText('');
      }
    };

    recognition.onstart = () => {
      setIsListening(true);
      resetSilenceTimer();
    };

    recognitionRef.current = recognition;
    recognition.start();
  }, [SpeechRecognitionAPI, resetSilenceTimer, cleanupBrowserSTT, cleanupFallback, startFallbackRecognition]);

  // cleanup: 组件卸载时停止识别
  useEffect(() => {
    return () => {
      if (silenceTimerRef.current) {
        clearTimeout(silenceTimerRef.current);
      }
      cleanupBrowserSTT();
      cleanupFallback();
    };
  }, [cleanupBrowserSTT, cleanupFallback]);

  return {
    isListening,
    isSupported,
    interimText,
    finalText,
    error,
    isFallbackMode,
    startListening,
    stopListening,
    resetText,
  };
}
