import { Config, Context } from "../context";
import { PluginManager } from "../plugin-manager";

/**
 * @description: 语音识别
 */
export class SpeechRecognition {
  context: Context;

  pluginManager: PluginManager;

  /**
   * @description: 构造函数
   * @param {Config} config 配置
   * @return {void} void
   */
  constructor(config?: Config) {
    this.context = new Context({ speechRecognition: this, config });
    this.pluginManager = new PluginManager(this.context);
    this.pluginManager.callPlugin("onInit");
  }

  /**
   * @description: 开始语音识别
   * @param {string} url 服务地址
   * @return {*} void
   */
  start = (config: { url: string }) => {
    const { url } = config;
    if (!url) throw new Error("url is required");
    this.listen();
    this.context.updateConfig(config);
    this.pluginManager.callPlugin("onWsConnect");
  };

  reStart = (config: { url: string }) => {
    const { url } = config;
    if (!url) throw new Error("url is required");
    const { connection } = this.context;
    connection.removeAllListeners();
    this.listen();
    this.context.updateConfig(config);
    this.pluginManager.callPlugin("onWsConnect");
  };

  // isReadyToSendAudio
  // packages/core-asr/src/connection/Connection.ts ——>  send ——> run-task

  /**
   * @description: 停止语音识别
   * @return {*} void
   */
  stop = () => {
    this.pluginManager.callPlugin("onBeforeStop");
  };

  /**
   * @description: 销毁语音识别
   * @return {*} void
   */
  destroy = () => {
    this.pluginManager.callPlugin("onDestroy");
    this.pluginManager.unregisterAllPlugin();
  };

  /**
   * @description: 注册内部监听事件
   * @return {*} void
   */
  private listen = () => {
    console.log("注册");
    this.listenStarted();
    this.listenMessage();
    this.listenStopped();
    this.listenError();
  };

  /**
   * @description: 监听开始事件
   * @return {*} void
   */
  private listenStarted = () => {
    const { recorder, connection } = this.context;
    const isStarted = {
      recorder: false,
      connection: false,
    };
    const started = () => {
      if (isStarted.recorder && isStarted.connection) {
        this.pluginManager.callPlugin("onStarted");
      }
    };

    recorder.on("start", () => {
      isStarted.recorder = true;
      started();
    });
    connection.on("open", () => {
      isStarted.connection = true;
      started();
    });
  };

  /**
   * @description: 监听消息事件
   * @return {*} void
   */
  private listenMessage = () => {
    const { connection } = this.context;
    connection.on("message", data => {
      this.pluginManager.callPlugin("onMessage", data);
    });
  };

  /**
   * @description: 监听停止事件
   * @return {*} void
   */
  private listenStopped = () => {
    const { recorder, connection, timer } = this.context;
    const isStopped = {
      recorder: false,
      connection: false,
    };
    const stopped = () => {
      if (isStopped.recorder && isStopped.connection) {
        timer.stop();
        this.pluginManager.callPlugin("onStopped");

        timer.removeAllListeners();
        recorder.removeAllListeners();
        connection.removeAllListeners();
      }
    };

    recorder.on("stop", () => {
      isStopped.recorder = true;
      stopped();
    });
    connection.on("close", () => {
      isStopped.connection = true;
      stopped();
    });
  };

  /**
   * @description: 监听错误事件
   * @return {*} void
   */
  private listenError = () => {
    const { recorder, connection } = this.context;
    const error = (type: "recorder" | "connection", data: any) => {
      this.pluginManager.callPlugin("onError", { type, data });
    };
    recorder.on("error", ({ data }) => error("recorder", data));
    connection.on("error", data => {
      error("connection", data);
    });
  };
}
