import { useRef, useState, useEffect, useCallback, useMemo } from "react";
import { SpeechRecognition, StartPlugin, NoSleepPlugin } from "@tingwu/core-asr";
import { message } from "antd";
import { eSpeechRecognitionStatusType, iUseSpeechRecognitionType } from "./index.type";
import { useMeetingState } from "../use-meeting-state";
import { nanoid } from "nanoid";
import { RealtimeRecordPlugin, getSendMessage } from "../../utils";
import { PingCommand } from "../../lib";
import { getTokens, websocketUrl } from "@tingwu/service";

let timmer: any = null;

export const useSpeechRecognition = (props: iUseSpeechRecognitionType) => {
  const { dataId, appId, meetingJoinUrl, onMessage, postAgentRequest, onErrorMessage } = props;
  const [status, setStatus] = useState<eSpeechRecognitionStatusType>(
    eSpeechRecognitionStatusType.IDLE
  );
  const { updateStore: updateMeetingState } = useMeetingState();
  const speechRecognitionRef = useRef<SpeechRecognition>();
  const pingCommandRef = useRef<PingCommand>();
  const socketContext = useRef<any>();

  const handleMessage = useCallback(
    (data: any, context: any) => {
      socketContext.current = context;
      onMessage?.(data, context);
      pingCommandRef.current?.onMessage(data);
    },
    [onMessage]
  );
  const handleOnError = (error: any) => {
    if (timmer) {
      clearTimeout(timmer);
    }
    if (socketContext.current?.connection?.connectCount >= 4) {
      onErrorMessage?.(error);
    } else {
      timmer = setTimeout(async () => {
        // 重新连接
        console.log("重新连接err");
        await reStartRecording();
      }, 6000);
    }
  };

  const aliAsrConfig = useMemo(
    () => ({
      startPayload: { dataId },
      onMessage: handleMessage,
      onErrorMessage: handleOnError,
      setStatus,
    }),
    [dataId, handleMessage]
  );

  const [isRecording, setIsRecording] = useState(false);
  const [isPaused, setIsPaused] = useState(false);

  // 初始化音频
  const initAudio = useCallback(async () => {
    if (!dataId) return;
    try {
      // 开始调用
      speechRecognitionRef.current = new SpeechRecognition({
        plugins: [
          StartPlugin,
          {
            plugin: RealtimeRecordPlugin,
            config: aliAsrConfig,
          },
          NoSleepPlugin,
        ],
        sendAudioDataWhenStarted: true,
      });
      speechRecognitionRef.current.start({ url: meetingJoinUrl });
      pingCommandRef.current = new PingCommand(
        speechRecognitionRef.current?.context,
        { sendPing },
        reStartRecording
      );
      pingCommandRef.current.onReady();
      setIsRecording(true);
      setIsPaused(false);
    } catch (error) {
      console.error("初始化音频失败:", error);
      message.error("初始化音频失败");
      setStatus(eSpeechRecognitionStatusType.ERROR);
    }
  }, [dataId, meetingJoinUrl, aliAsrConfig]);

  // 获取临时token
  const getWssUrl = useCallback(async () => {
    try {
      const result = await getTokens();
      if (result?.token) {
        updateMeetingState(draft => {
          draft.createTaskOutput.meetingJoinUrl = `${websocketUrl}?api_key=${result.token}`;
        });
        return `${websocketUrl}?api_key=${result.token}`;
      }
      return meetingJoinUrl;
    } catch (error) {
      return meetingJoinUrl;
    }
  }, [getTokens, updateMeetingState]);

  const sendPing = useCallback(() => {
    const connection = socketContext.current?.connection;
    if (connection) {
      connection.send(JSON.stringify(getSendMessage({ taskId: nanoid(16), action: "continue" })));
    }
  }, [socketContext.current]);

  // 开始录音
  const startRecording = useCallback(async () => {
    if (isRecording && !isPaused) {
      return; // 已经在录音中
    }

    if (isPaused) {
      // 恢复录音
      speechRecognitionRef.current?.stop();
      setIsPaused(false);
      setIsRecording(true);
      setStatus(eSpeechRecognitionStatusType.RECORDING);
    }
    // 开始新的录音
    await initAudio();
  }, [isRecording, isPaused, initAudio]);

  // 重新连接
  const reStartRecording = useCallback(async () => {
    if (speechRecognitionRef.current) {
      const { recorder, connection } = speechRecognitionRef.current.context;
      connection.close();
      recorder.stop();
      const result = await getWssUrl();
      pingCommandRef.current?.stopPingPong();
      speechRecognitionRef.current?.reStart({ url: result });
      pingCommandRef.current?.onReady();
    }
  }, [speechRecognitionRef.current, getWssUrl, pingCommandRef.current]);

  // 暂停录音
  const pauseRecording = useCallback(() => {
    if (!isRecording || isPaused) {
      return;
    }
    const connection = socketContext.current?.connection;
    if (connection) {
      connection.send(JSON.stringify(getSendMessage({ taskId: nanoid(16), action: "stop" })));
    }

    setIsPaused(true);
    setStatus(eSpeechRecognitionStatusType.PAUSED);
  }, [isRecording, isPaused]);

  // 停止录音并调用createTask接口
  const stopRecording = useCallback(
    async (dataId: string) => {
      if (!isRecording && !isPaused) {
        return;
      }

      try {
        // 停止录音
        const connection = socketContext.current?.connection;
        if (connection) {
          connection.send(JSON.stringify(getSendMessage({ taskId: nanoid(16), action: "stop" })));
        }
        setIsRecording(false);
        setIsPaused(false);
        setStatus(eSpeechRecognitionStatusType.STOPPING);

        const params = {
          input: {
            task: "createTask",
            type: "realtime",
            appId,
            dataId,
          },
        };

        const res = await postAgentRequest(params);
        if (res?.code && res?.message) {
          message.error(res?.message);
          return false;
        }

        updateMeetingState(draft => {
          draft.currentTaskIsMeeting = false;
        });
        return true;
      } catch (error) {
        console.error("停止录音或调用接口失败:", error);
        message.error("停止录音失败");
        setStatus(eSpeechRecognitionStatusType.ERROR);
        return false;
      }
    },
    [isRecording, isPaused, appId, postAgentRequest, updateMeetingState]
  );

  // 清理资源
  useEffect(() => {
    return () => {
      if (speechRecognitionRef.current) {
        speechRecognitionRef.current.stop();
        speechRecognitionRef.current.destroy();
      }
    };
  }, []);

  return {
    status,
    isPaused,
    isRecording,
    startRecording,
    pauseRecording,
    stopRecording,
  };
};
