type BrowserSpeechRecognition = SpeechRecognition & {
  onresult: ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => void) | null;
  onerror: ((this: SpeechRecognition, ev: SpeechRecognitionErrorEvent) => void) | null;
  onend: ((this: SpeechRecognition, ev: Event) => void) | null;
};

type SpeechRecognitionCtor = new () => BrowserSpeechRecognition;

declare global {
  interface Window {
    webkitSpeechRecognition?: SpeechRecognitionCtor;
  }
}

export function isSpeechRecognitionSupported() {
  return typeof window !== 'undefined' && !!(window.SpeechRecognition || window.webkitSpeechRecognition);
}

function getSpeechRecognitionCtor(): SpeechRecognitionCtor | null {
  if (typeof window === 'undefined') return null;
  return window.SpeechRecognition ?? window.webkitSpeechRecognition ?? null;
}

export function createLiveSpeechRecognition({
  onInterim,
  onFinal,
  onError,
}: {
  onInterim: (text: string) => void;
  onFinal: (text: string) => void;
  onError: (message: string) => void;
}) {
  const Ctor = getSpeechRecognitionCtor();
  if (!Ctor) return null;

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

  let active = false;
  let restarting = false;
  let restartTimer: number | null = null;

  const clearRestartTimer = () => {
    if (restartTimer != null) {
      window.clearTimeout(restartTimer);
      restartTimer = null;
    }
    restarting = false;
  };

  recognition.onresult = (event) => {
    let interim = '';
    let finals = '';
    for (let i = event.resultIndex; i < event.results.length; i += 1) {
      const result = event.results[i];
      const chunk = result[0]?.transcript ?? '';
      if (result.isFinal) finals += chunk;
      else interim += chunk;
    }
    if (finals) onFinal(finals);
    onInterim(interim);
  };

  recognition.onerror = (event) => {
    if (event.error === 'aborted' || event.error === 'no-speech') return;
    if (event.error === 'not-allowed') {
      onError('请在浏览器设置中允许麦克风');
      return;
    }
    if (event.error === 'network') {
      onError('语音识别网络异常，请检查连接');
      return;
    }
    onError(`语音识别失败：${event.error}`);
  };

  recognition.onend = () => {
    if (!active || restarting) return;
    restarting = true;
    restartTimer = window.setTimeout(() => {
      restartTimer = null;
      restarting = false;
      if (!active) return;
      try {
        recognition.start();
      } catch {
        // ignore restart races
      }
    }, 120);
  };

  return {
    start() {
      clearRestartTimer();
      active = true;
      try {
        recognition.start();
      } catch (err) {
        active = false;
        const message = err instanceof Error ? err.message : String(err);
        if (/already started/i.test(message)) {
          window.setTimeout(() => {
            if (!active) return;
            try {
              recognition.start();
            } catch {
              onError('无法启动语音识别，请关闭后重试');
            }
          }, 150);
          return;
        }
        onError('无法启动语音识别，请重试');
      }
    },
    stop() {
      active = false;
      clearRestartTimer();
      recognition.stop();
    },
    abort() {
      active = false;
      clearRestartTimer();
      recognition.abort();
    },
  };
}
