// import Base64 from "crypto-js/enc-base64";
import CryptoJS from "crypto-js";
import AudioPlayer from "./audioPlayer.esm";
import Base64 from "./base64";

export default class TtsVoice {
  appId = "";
  apiSecret = "";
  apiKey = "";
  ttsWS = null;
  status = "UNDEFINED";
  statusStr = "";
  audioPlayer = null;
  text = "";
  blob = "";
  cb = () => {};
  blobDoneCb = () => {};
  constructor(params) {
    this.appId = params.appId;
    this.apiSecret = params.apiSecret;
    this.apiKey = params.apiKey;
    if (params.cb) {
      this.cb = params.cb;
    }
    if (params.blobDoneCb) {
      this.blobDoneCb = params.blobDoneCb;
    }
    this.audioPlayer = new AudioPlayer();
    this.audioPlayer.onPlay = () => {
      this.changeBtnStatus("PLAY");
    };
    this.audioPlayer.onStop = (audioDatas) => {
      console.log(audioDatas);
      this.status === "PLAY" && this.changeBtnStatus("STOP");
    };
  }
  setText(text) {
    this.text = text;
  }
  changeBtnStatus(status) {
    this.status = status;
    if (status === "UNDEFINED") {
      this.statusStr = "立即合成";
    } else if (status === "CONNECTING") {
      this.statusStr = "正在合成";
    } else if (status === "PLAY") {
      this.statusStr = "停止播放";
    } else if (status === "STOP") {
      this.statusStr = "重新播放";
    }
    const _this = this;
    this.cb({ status, statusStr: _this.statusStr });
  }
  encodeText(text, type) {
    if (type === "unicode") {
      let buf = new ArrayBuffer(text.length * 4);
      let bufView = new Uint16Array(buf);
      for (let i = 0, strlen = text.length; i < strlen; i++) {
        bufView[i] = text.charCodeAt(i);
      }
      let binary = "";
      let bytes = new Uint8Array(buf);
      let len = bytes.byteLength;
      for (let i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
      }
      return window.btoa(binary);
    } else {
      return Base64.encode(text);
    }
  }
  getWebSocketUrl() {
    let apiKey = this.apiKey;
    let apiSecret = this.apiSecret;
    var url = "wss://tts-api.xfyun.cn/v2/tts";
    var host = location.host;
    var date = new Date().toGMTString();
    var algorithm = "hmac-sha256";
    var headers = "host date request-line";
    var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`;
    var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
    var signature = CryptoJS.enc.Base64.stringify(signatureSha);
    var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
    var authorization = btoa(authorizationOrigin);
    url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
    return url;
  }
  stopConnect() {
    this.changeBtnStatus("UNDEFINED");
    this.ttsWS?.close();
    this.audioPlayer.reset();
  }
  action(text) {
    if (text && typeof text === "string") {
      if (text !== this.text) {
        this.changeBtnStatus("UNDEFINED");
      }
      this.setText(text);
    }
    if (this.status === "UNDEFINED") {
      // 开始合成

      this.connect();
    } else if (this.status === "CONNECTING") {
      // 停止合成
      this.changeBtnStatus("UNDEFINED");
      this.ttsWS?.close();
      this.audioPlayer.reset();
      return;
    } else if (this.status === "PLAY") {
      this.audioPlayer.stop();
    } else if (this.status === "STOP") {
      this.audioPlayer.play();
    }
  }
  connect() {
    this.ttsWS?.close();
    this.blob = "";
    this.blobDoneCb && this.blobDoneCb(this.blob);
    const text = this.text || "请输入文字！";
    const appId = this.appId;
    const apiKey = this.apiKey;
    const apiSecret = this.apiSecret;
    const url = this.getWebSocketUrl(apiKey, apiSecret);
    if ("WebSocket" in window) {
      this.ttsWS = new WebSocket(url);
    } else if ("MozWebSocket" in window) {
      this.ttsWS = new window.MozWebSocket(url);
    } else {
      alert("浏览器不支持WebSocket");
      return;
    }
    this.changeBtnStatus("CONNECTING");
    const _this = this;
    this.ttsWS.onopen = () => {
      _this.audioPlayer.start({
        autoPlay: true,
        sampleRate: 16000,
        resumePlayDuration: 1000,
      });
      _this.changeBtnStatus("PLAY");
      var tte = "UTF8";
      var params = {
        common: {
          app_id: appId,
        },
        business: {
          aue: "raw",
          auf: "audio/L16;rate=16000",
          vcn: "50",
          speed: 50,
          volume: 50,
          pitch: 50,
          bgs: 1,
          tte,
        },
        data: {
          status: 2,
          text: _this.encodeText(text, tte),
        },
      };
      _this.ttsWS.send(JSON.stringify(params));
    };
    this.ttsWS.onmessage = (e) => {
      let jsonData = JSON.parse(e.data);
      // 合成失败
      if (jsonData.code !== 0) {
        console.error(jsonData);
        _this.changeBtnStatus("UNDEFINED");
        return;
      }
      _this.audioPlayer.postMessage({
        type: "base64",
        data: jsonData.data.audio,
        isLastData: jsonData.data.status === 2,
      });
      if (jsonData.code === 0 && jsonData.data.status === 2) {
        _this.ttsWS.close();
        setTimeout(() => {
          _this.blob = this.audioPlayer.getAudioDataBlob("wav");
          _this.blobDoneCb && _this.blobDoneCb(_this.blob);
        });
      }
    };
    _this.ttsWS.onerror = (e) => {
      console.error(e);
    };
    _this.ttsWS.onclose = (e) => {
      console.log(e);
    };
  }
  download() {
    const blob = this.audioPlayer.getAudioDataBlob("wav");
    if (!blob) {
      return;
    }
    let defaultName = new Date().getTime();
    let node = document.createElement("a");
    node.href = window.URL.createObjectURL(blob);
    node.download = `${defaultName}.wav`;
    node.click();
    node.remove();
  }
  reset() {
    this.ttsWS?.close();
    this.text = "";
    this.blob = "";
    this.changeBtnStatus("UNDEFINED");
    this.audioPlayer?.reset();
  }
}
