/*
 * @Author: 吴文洁
 * @Date: 2020-03-18 10:01:28
 * @LastEditors: fusanqiasng
 * @LastEditTime: 2021-06-22 17:01:05
 * @Description: 录音组件
 */

import React, { Component } from 'react';
import { Button, Modal } from 'antd';

import UploadOss from '@/core/upload';
import { RECORD_ERROR } from '@/common/constants/academic';
import AudioRecorder from '../components/audioRecord';

import './XMRecord.less';

class XMRecord extends Component {
  constructor(props) {
    super(props);
    //从麦克风获取的音频流
    this.mAudioContext = null;
    this.mAudioFromMicrophone = null;
    this.mMediaRecorder = null;
    this.mChunks = [];

    this.state = {
      isFinished: true,
      recordTime: 0,
    };
  }

  componentDidMount() {
    // 获取录音设备
    this.getAudioRecorderDevice();
  }

  componentWillUnmount() {}

  getAudioRecorderDevice = () => {
    //仅用来进行录音
    const constraints = { audio: true };
    // 老的浏览器可能根本没有实现 mediaDevices，所以我们可以先设置一个空的对象
    if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {};
    }
    // 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
    // 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
    if (navigator.mediaDevices.getUserMedia === undefined) {
      navigator.mediaDevices.getUserMedia = function (constraints) {
        // 首先，如果有getUserMedia的话，就获得它
        var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
        if (!getUserMedia) {
          return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
        }

        // 否则，为老的navigator.getUserMedia方法包裹一个Promise
        return new Promise(function (resolve, reject) {
          getUserMedia.call(navigator, constraints, resolve, reject);
        });
      };
    }
  };

  openDeviceFailure = (reason) => {
    const { title = '麦克风调用错误', content = '请检查麦克风是否可用' } = RECORD_ERROR[reason.name] || {};
    Modal.info({
      title,
      content,
      okText: '我知道了',
    });
  };

  handleCloseConfirm = () => {
    this.$confirm = null;
    this.forceUpdate();
  };

  handleStartRecord = () => {
    navigator.mediaDevices
      .getUserMedia({
        audio: true,
      })
      .then((stream) => {
        this.mMediaRecorder = new AudioRecorder(stream);
        this.mMediaRecorder.start();
        this.handleCountTime();
      }, this.openDeviceFailure);
  };

  onProcessData = (audioData) => {
    this.mChunks.push(audioData.data);
  };

  handleCountTime = () => {
    const { maxTime = 180 } = this.props;
    this.setState({ isFinished: false });

    // 开始计时
    this.timer = window.setInterval(() => {
      const { recordTime } = this.state;
      if (recordTime > maxTime - 1) {
        window.clearInterval(this.timer);
        this.handleFinishRecord();
        return;
      }
      this.setState({
        recordTime: this.state.recordTime + 1,
      });
    }, 1000);
  };

  handleFinishRecord = () => {
    if (this.mMediaRecorder) {
      this.mMediaRecorder.stop();
    }
    const blob = this.mMediaRecorder.upload();
    UploadOss.uploadBlobToOSS(blob, window.random_string(16) + '.wav').then((mp3URL) => {
      const { recordTime } = this.state;
      this.props.onFinish(mp3URL, recordTime * 1000);
      this.setState({
        recordTime: 0,
        isFinished: true,
      });
      window.clearInterval(this.timer);
    });
  };

  // 格式化当前录音时长
  formatRecordTime = (timeStamp) => {
    let minutes = Math.floor(timeStamp / 60);
    let seconds = timeStamp % 60;

    minutes = minutes < 10 ? `0${minutes}` : minutes;
    seconds = seconds < 10 ? `0${seconds}` : seconds;

    return `${minutes}:${seconds}`;
  };

  handleCancel = () => {
    if (this.mMediaRecorder) {
      this.mMediaRecorder.stop();
    }
    window.clearInterval(this.timer);
    this.setState(
      {
        recordTime: 0,
        isFinished: true,
      },
      () => {
        this.props.onCancel();
      }
    );
  };

  render() {
    const { isFinished, recordTime } = this.state;
    const { visible, maxTime = 180 } = this.props;
    return (
      <div className={`xm-record ${visible ? 'visible' : 'hidden'}`}>
        <div className='record-left'>
          <div className='text'>
            {isFinished ? (
              <img style={{ width: 14, height: 14 }} src='https://image.xiaomaiketang.com/xm/xCahGm2Q2J.png' />
            ) : (
              <img src='https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1584607726775.png' />
            )}
            {isFinished ? <span>录音</span> : <span>录音中...</span>}
          </div>
          <div className='time'>{`${this.formatRecordTime(recordTime)}/${this.formatRecordTime(maxTime)}`}</div>
        </div>

        <div className='btn-wrapper'>
          <Button onClick={this.handleCancel}>取消</Button>
          {isFinished ? (
            <Button type='primary' onClick={this.handleStartRecord}>
              开始
            </Button>
          ) : (
            <Button type='primary' className='finish' onClick={this.handleFinishRecord}>
              完成
            </Button>
          )}
        </div>
      </div>
    );
  }
}

export default XMRecord;
