import { Record, CATEGORIES } from '../../configuration/constants'

//未实现向后端发送数据

export default {

  // 组件名称
  name: Record,

  // 前面板html模板
  viewTemplate() {
    return `
      <div data-gjs-type="${Record}" class="${Record}">
        <button id='btn_start' class="btn_start ant-btn ant-btn-default ant-btn-round ant-btn-lg" style='display:inline-block'>按住录音</button>
        <audio class='test_audio' controls="controls"></audio>
      </div>
    `
  },
  // 前面板html样式
  viewStyle() {
    return `
      <style>
        .test_audio {
          vertical-align: middle;
          margin-left: 10px;
        }
      </style>
    `;
  },

  // 编辑器右侧块管理器中显示属性配置
  blockOptions() {
    return {
      category: CATEGORIES.MEDIA,
      label: "录音组件",
      attributes: { class: 'fa fa-microphone' },
    };
  },

  spOptions() {
    return {
      label: '录音组件',
      icon: 'globe',
      author: '宗介',
      email: 'zongjie.wxt@xuelangyun.com',
      docUrl: "https://xuelangyun.yuque.com/docs/share/d12fd374-357a-4e45-9d14-1b31ed50947d?# 《录音组件》",
      outPorts: [
        {
          uuid: 'out1',
          subType: 'all',
          description: {
            zh_CN: '输出1'
          }
        }
      ]
    }
  },

  // 组件属性
  componentOptions() {
    return {
      droppable: false,
      resizable: true,
      dmode: 'absolute',
      highlightable: false,
      childrenStatic: true,
      traits: []
    }
  },

  onModelScript() {
    const self = this;

    let leftDataList = [], rightDataList = [], mediaNode = null, jsNode = null;
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia
    const startButton = this.querySelector('.btn_start');

    let mStream = null;
    let recordStatus = 'waiting';

    startButton.addEventListener("mousedown", runRecord);
    startButton.addEventListener("mouseup", stopRecord);

    // 主程序
    function runRecord() {
      navigator.mediaDevices.getUserMedia({
        audio: true, video: false
      }).then(mediaStream => {
        mStream = mediaStream;
        if (recordStatus == 'end') {
          //清除上次录音缓存
          clearRecord(mediaStream);
        }

        beginRecord(mediaStream);
      }, error => {
        alert('出错，请确保已允许浏览器获取录音权限');
      });

    }

    function createJSNode(audioContext) {
      const BUFFER_SIZE = 4096;
      const INPUT_CHANNEL_COUNT = 2;
      const OUTPUT_CHANNEL_COUNT = 2;
      // createJavaScriptNode已被废弃
      let creator = audioContext.createScriptProcessor || audioContext.createJavaScriptNode;
      creator = creator.bind(audioContext);
      return creator(BUFFER_SIZE, INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT);
    }

    function onAudioProcess(event) {
      let audioBuffer = event.inputBuffer;
      let leftChannelData = audioBuffer.getChannelData(0), rightChannelData = audioBuffer.getChannelData(1);

      leftDataList.push(leftChannelData.slice(0));
      rightDataList.push(rightChannelData.slice(0));
    }

    function beginRecord(mediaStream) {
      recordStatus = 'recording'

      let audioContext = new (window.AudioContext || window.webkitAudioContext);
      mediaNode = audioContext.createMediaStreamSource(mediaStream);

      // 创建一个jsNode
      jsNode = createJSNode(audioContext);
      // 需要连到扬声器消费掉outputBuffer，process回调才能触发
      // 并且由于不给outputBuffer设置内容，所以扬声器不会播放出声音
      jsNode.connect(audioContext.destination);
      jsNode.onaudioprocess = onAudioProcess;
      // 把mediaNode连接到jsNode
      mediaNode.connect(jsNode);
      // 隐藏录音按钮
      startButton.innerText = "松开停止";
    }

    function stopRecord() {
      // 停止录音
      if (mStream !== null) {
        recordStatus = 'end'
        mStream.getAudioTracks()[0].stop();
        mediaNode.disconnect();
        jsNode.disconnect();
  
        let leftData = mergeArray(leftDataList),
          rightData = mergeArray(rightDataList);
        let allData = interleaveLeftAndRight(leftData, rightData);
        let wavBuffer = createWavFile(allData);
  
        playRecord(wavBuffer);
        // 隐藏停止按钮
        startButton.innerText = "按住录音";

        mStream = null;
      }
    }

    // 清理左右音轨缓存
    function clearRecord(mediaStream) {
      leftDataList = [], rightDataList = []
    };

    // 合并声道
    function mergeArray(list) {
      let length = list.length * list[0].length;
      let data = new Float32Array(length),
        offset = 0;
      for (let i = 0; i < list.length; i++) {
        data.set(list[i], offset);
        offset += list[i].length;
      }
      return data;
    }

    // 前面板播放录音，并可下载.wav格式
    function playRecord(arrayBuffer) {
      let blob = new Blob([new Uint8Array(arrayBuffer)], { type: 'audio/wav' });
      let blobUrl = URL.createObjectURL(blob);

      // 创建上传oss的音频文件
      const recordFile = new File([blob], 'recordfile.wav', { type: blob.type });

      document.querySelector('.test_audio').src = blobUrl;

      if (window.spSocket) {
        const oss_path = 'studio/' + window.appConfig.userId + '/' + window.appConfig.id + '/' + 'tmp/'; // 上传oss的位置
        window.spSocket.sendFile(oss_path, [recordFile]).then((keys) => {
          window.spSocket.send({
            eventName: `call-${self.id}`,
            data: {
              out1: keys
            }
          })
        })
      } else {
        console.log('上传失败:', window.spSocket)
      }
    }

    // 前面板下载weba格式录音,未启用
    function downloadRecordedAudio(blobUrl) {
      var curDate = new Date();
      $(self).find("#btn_download").attr("href", blobUrl);

      var curDatetimeStr = curDate.toISOString().slice(0, 19);
      var curDatetimeStrName = curDatetimeStr.substring(0, 13) + curDatetimeStr.substring(14, 15) + curDatetimeStr.substring(17, 19)

      var recordedAudioFilename = curDatetimeStrName + ".weba";
    }

    // 交叉合并左右声道的数据
    function interleaveLeftAndRight(left, right) {
      let totalLength = left.length + right.length;
      let data = new Float32Array(totalLength);
      for (let i = 0; i < left.length; i++) {
        let k = i * 2;
        data[k] = left[i];
        data[k + 1] = right[i];
      }
      return data;
    }

    function createWavFile(audioData) {
      const WAV_HEAD_SIZE = 44;
      let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE),
        // 需要用一个view来操控buffer
        view = new DataView(buffer);
      // 写入wav头部信息
      // RIFF chunk descriptor/identifier
      writeUTFBytes(view, 0, 'RIFF');
      // RIFF chunk length
      view.setUint32(4, 44 + audioData.length * 2, true);
      // RIFF type
      writeUTFBytes(view, 8, 'WAVE');
      // format chunk identifier
      // FMT sub-chunk
      writeUTFBytes(view, 12, 'fmt ');
      // format chunk length
      view.setUint32(16, 16, true);
      // sample format (raw)
      view.setUint16(20, 1, true);
      // stereo (2 channels)
      view.setUint16(22, 2, true);
      // sample rate
      view.setUint32(24, 44100, true);
      // byte rate (sample rate * block align)
      view.setUint32(28, 44100 * 2, true);
      // block align (channel count * bytes per sample)
      view.setUint16(32, 2 * 2, true);
      // bits per sample
      view.setUint16(34, 16, true);
      // data sub-chunk
      // data chunk identifier
      writeUTFBytes(view, 36, 'data');
      // data chunk length
      view.setUint32(40, audioData.length * 2, true);
      let length = audioData.length;
      let index = 44;
      let volume = 1;
      for (let i = 0; i < length; i++) {
        view.setInt16(index, audioData[i] * (0x7FFF * volume), true);
        index += 2;
      }
      return buffer;
    }

    function writeUTFBytes(view, offset, string) {
      var lng = string.length;
      for (var i = 0; i < lng; i++) {
        view.setUint8(offset + i, string.charCodeAt(i));
      }
    }
  },

  onViewInit() {
    const evn = `change:docUrl change:traits`;

    this.listenTo(this.model, evn, this.updateScript);
    this.listenTo(this.model, evn, this.em.handleUpdates.bind(this.em));
  }
}

