import { useCallback, useEffect, useRef, useState } from 'react';
import { useVoiceSession } from '../hooks/useVoiceSession';
import { shouldShowVoiceInputControl, isVoiceInputAvailable } from '../voice/capabilities';
import { isWechatBrowser } from '../utils/wechat';
import {
  checkWechatVoiceApis,
  isWechatVoiceReady,
  prepareWechatVoiceSdk,
  startWechatVoiceRecord,
  stopWechatVoiceRecord,
  translateWechatVoice,
} from '../voice/wechatVoice';

function MicIcon() {
  return (
    <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
      <path
        fill="currentColor"
        d="M12 15c1.66 0 3-1.34 3-3V6c0-1.66-1.34-3-3-3S9 4.34 9 6v6c0 1.66 1.34 3 3 3zm5-3c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-2.08c3.39-.49 6-3.39 6-6.92h-2z"
      />
    </svg>
  );
}

function VoiceActiveIcon() {
  return (
    <span className="voice-btn-eq" aria-hidden="true">
      <span className="voice-btn-eq-bar" />
      <span className="voice-btn-eq-bar" />
      <span className="voice-btn-eq-bar" />
      <span className="voice-btn-eq-bar" />
    </span>
  );
}

export function VoiceInputButton({
  disabled = false,
  onTranscript,
  onLiveTranscript,
  onVoiceStart,
  onVoiceComplete,
  onRecordingChange,
  onError,
  stopSignal = 0,
}: {
  disabled?: boolean;
  onTranscript?: (text: string) => void;
  onLiveTranscript?: (text: string) => void;
  onVoiceStart?: () => void;
  onVoiceComplete?: () => void;
  onRecordingChange?: (recording: boolean) => void;
  onError?: (message: string) => void;
  stopSignal?: number;
}) {
  const [available, setAvailable] = useState(true);
  const [browserActive, setBrowserActive] = useState(false);
  const [wechatReady, setWechatReady] = useState(false);
  const [wechatApiAvailable, setWechatApiAvailable] = useState(false);
  const [wechatPrepareError, setWechatPrepareError] = useState<string | null>(null);
  const [wechatPhase, setWechatPhase] = useState<'idle' | 'requesting' | 'recording' | 'transcribing'>('idle');
  const wechatPhaseRef = useRef(wechatPhase);
  const pendingWechatStopRef = useRef(false);
  const startedAtRef = useRef(0);
  const startingRef = useRef(false);
  const browserCommittedRef = useRef(false);
  const prevRecordingRef = useRef(false);
  const lastStopSignalRef = useRef(stopSignal);

  useEffect(() => {
    setAvailable(isVoiceInputAvailable());
  }, []);

  useEffect(() => {
    wechatPhaseRef.current = wechatPhase;
  }, [wechatPhase]);

  const wechatMode = isWechatBrowser();
  const wechatBusy = wechatPhase === 'requesting' || wechatPhase === 'transcribing';
  const wechatRecording = wechatPhase === 'recording';
  const wechatUnavailable = wechatMode && (!wechatReady || !wechatApiAvailable || !!wechatPrepareError);
  const {
    phase: browserPhase,
    text: browserText,
    liveRecognition,
    stopListening,
    finishFallbackRecording,
    resetSession,
  } = useVoiceSession({
    active: !wechatMode && browserActive && !disabled,
    onError,
  });
  const browserBusy = browserPhase === 'requesting' || browserPhase === 'transcribing';
  const browserListening = browserPhase === 'listening';
  const recording = wechatRecording || browserListening;
  const busy = wechatMode ? wechatBusy : browserBusy;
  const blocked = disabled || !available || busy;

  useEffect(() => {
    if (recording && !prevRecordingRef.current) {
      onVoiceStart?.();
    }
    prevRecordingRef.current = recording;
    onRecordingChange?.(recording);
  }, [onRecordingChange, onVoiceStart, recording]);

  useEffect(() => {
    if (wechatMode || !browserListening || !onLiveTranscript) return;
    onLiveTranscript(browserText);
  }, [browserListening, browserText, onLiveTranscript, wechatMode]);

  useEffect(() => {
    if (wechatMode || !browserActive) return;
    if (browserPhase === 'ready') {
      const transcript = browserText.trim();
      if (transcript && !browserCommittedRef.current) {
        browserCommittedRef.current = true;
        if (liveRecognition) {
          onVoiceComplete?.();
        } else {
          onTranscript?.(transcript);
        }
      }
      setBrowserActive(false);
      return;
    }
    if (browserPhase === 'error') {
      setBrowserActive(false);
    }
  }, [browserActive, browserPhase, browserText, liveRecognition, onTranscript, onVoiceComplete, wechatMode]);

  useEffect(() => {
    if (browserActive || wechatMode) return;
    browserCommittedRef.current = false;
    resetSession();
  }, [browserActive, resetSession, wechatMode]);

  useEffect(() => {
    if (stopSignal === lastStopSignalRef.current) return;
    lastStopSignalRef.current = stopSignal;
    setBrowserActive(false);
    if (wechatMode) {
      void stopWechatVoiceRecord().catch(() => {
        // best-effort stop when the parent explicitly ends the current draft
      });
      setWechatPhase('idle');
      pendingWechatStopRef.current = false;
    }
  }, [stopSignal, wechatMode]);

  useEffect(() => {
    if (!wechatMode) return;
    let cancelled = false;
    setWechatReady(isWechatVoiceReady());
    setWechatApiAvailable(false);
    prepareWechatVoiceSdk()
      .then(() => {
        if (cancelled) return;
        setWechatReady(true);
        setWechatPrepareError(null);
        return checkWechatVoiceApis();
      })
      .then((result) => {
        if (cancelled || !result) return;
        const unavailable = ['startRecord', 'stopRecord', 'translateVoice'].filter((api) => result[api] === false);
        if (unavailable.length) {
          setWechatApiAvailable(false);
          setWechatPrepareError(`微信语音接口不可用：${unavailable.join(', ')}`);
          return;
        }
        setWechatApiAvailable(true);
      })
      .catch((err) => {
        if (cancelled) return;
        setWechatReady(false);
        setWechatApiAvailable(false);
        setWechatPrepareError(err instanceof Error ? err.message : '微信语音初始化失败');
      });
    return () => {
      cancelled = true;
    };
  }, [wechatMode]);

  const commitWechatTranscript = useCallback(
    (text: string) => {
      const value = text.trim();
      if (!value) {
        onError?.('未识别到语音，请重试');
        return;
      }
      onTranscript?.(value);
    },
    [onError, onTranscript],
  );

  const finishWechatRecording = useCallback(
    async (localId?: string) => {
      if (wechatPhaseRef.current === 'idle') return;
      const duration = Date.now() - startedAtRef.current;
      setWechatPhase('transcribing');
      try {
        if (duration < 500 && !localId) {
          try {
            await stopWechatVoiceRecord();
          } catch {
            // ignore best-effort cleanup for very short taps
          }
          onError?.('说话时间太短');
          return;
        }
        const voiceId = localId || (await stopWechatVoiceRecord());
        const text = await translateWechatVoice(voiceId);
        commitWechatTranscript(text);
      } catch (err) {
        onError?.(err instanceof Error ? err.message : '微信语音识别失败');
      } finally {
        pendingWechatStopRef.current = false;
        setWechatPhase('idle');
      }
    },
    [commitWechatTranscript, onError],
  );

  const beginWechatRecording = useCallback(
    async () => {
      if (startingRef.current || wechatPhaseRef.current !== 'idle') return;
      if (blocked) {
        if (!available) onError?.('当前浏览器不支持语音输入');
        return;
      }
      if (!isWechatVoiceReady() || !wechatApiAvailable) {
        setWechatReady(false);
        void prepareWechatVoiceSdk()
          .then(() => {
            setWechatReady(true);
            setWechatPrepareError(null);
            return checkWechatVoiceApis();
          })
          .then((result) => {
            if (!result) return;
            const unavailable = ['startRecord', 'stopRecord', 'translateVoice'].filter((api) => result[api] === false);
            if (unavailable.length) {
              setWechatApiAvailable(false);
              setWechatPrepareError(`微信语音接口不可用：${unavailable.join(', ')}`);
              return;
            }
            setWechatApiAvailable(true);
          })
          .catch((err) => {
            setWechatReady(false);
            setWechatApiAvailable(false);
            setWechatPrepareError(err instanceof Error ? err.message : '微信语音初始化失败');
          });
        onError?.(wechatPrepareError || '微信语音初始化中，请稍后再试');
        return;
      }
      pendingWechatStopRef.current = false;
      startedAtRef.current = Date.now();
      startingRef.current = true;
      setWechatPhase('requesting');
      try {
        await startWechatVoiceRecord((localId) => {
          void finishWechatRecording(localId);
        });
        setWechatPhase('recording');
        if (pendingWechatStopRef.current) {
          void finishWechatRecording();
        }
      } catch (err) {
        pendingWechatStopRef.current = false;
        setWechatPhase('idle');
        onError?.(err instanceof Error ? err.message : '微信语音启动失败');
      } finally {
        startingRef.current = false;
      }
    },
    [available, blocked, finishWechatRecording, onError, wechatApiAvailable, wechatPrepareError],
  );

  if (!shouldShowVoiceInputControl()) return null;

  return (
    <button
      type="button"
      className={`voice-btn${recording ? ' voice-btn-recording' : ''}${busy ? ' voice-btn-busy' : ''}${
        wechatMode ? ' voice-btn-wechat' : ''
      }`}
      disabled={blocked}
      aria-label="语音输入"
      title={
        available
          ? wechatMode
            ? wechatRecording
              ? '点击结束识别'
              : wechatUnavailable
                ? wechatPrepareError || '微信语音初始化中，请稍后再试'
                : '点击开始语音输入'
            : browserListening
              ? liveRecognition
                ? '点击结束听写'
                : '点击结束录音并识别'
              : browserBusy
                ? '正在识别…'
                : '点击开始语音输入'
          : '当前浏览器不支持麦克风，请改用文字输入'
      }
      onClick={() => {
        if (wechatMode) {
          if (wechatRecording) {
            void finishWechatRecording();
            return;
          }
          void beginWechatRecording();
          return;
        }
        if (blocked) {
          if (!available) onError?.('当前浏览器不支持语音输入');
          return;
        }
        if (browserListening) {
          if (liveRecognition) {
            stopListening();
          } else {
            void finishFallbackRecording();
          }
          return;
        }
        browserCommittedRef.current = false;
        setBrowserActive(true);
      }}
    >
      {busy ? (
        <span className="voice-btn-spinner" aria-hidden="true" />
      ) : recording ? (
        <VoiceActiveIcon />
      ) : (
        <MicIcon />
      )}
    </button>
  );
}
