class RtcClient {
  constructor(options) {
    this.sdkAppId_ = options.sdkAppId;
    this.userId_ = options.userId;
    this.userSig_ = options.userSig;
    this.roomId_ = options.roomId;
    this.role = options.role; // 用户的角色主播还是观众（这里的指的是trtc定义的anchor和audience）
    this.nick = options.nick;
    this.vueInstance = options.vueInstance;

    this.isJoined_ = false;
    this.isPublished_ = false;
    this.isAudioMuted = false;
    this.isVideoMuted = false;
    this.localStream_ = null;
    this.remoteStreams_ = [];
    this.members_ = new Map();
    this.inmembers_ = new Map();

    this.viewslist = [];
    this.isPushing = 0;

    try {
      this.client_ = TRTC.createClient({
        mode: 'live',
        sdkAppId: this.sdkAppId_,
        userId: this.userId_,
        userSig: this.userSig_
      });
      this.handleEvents();
    } catch (error) {
      console.log('创建client失败', error);
      this.vueInstance.reloadfn();
    }
  }

  // 加入房间
  async join() {
    if (this.isJoined_) {
      alert('抱歉，您已经在房间里面为了');
      return;
    }
    try {
      await this.client_.join({
        roomId: this.roomId_,
        role: this.role
      });
      console.log('加入房间trtc成功');
      this.isJoined_ = true;
      // 不要指定cameraId/microphoneId以避免过度约束
      this.localStream_ = TRTC.createStream({
        audio: true,
        video: false,
        userId: this.userId_,
        mirror: true
      });
      this.startRTC();
    } catch (e) {
      console.error('加入房间失败 ' + e);
      this.vueInstance.reloadfn();
    }
  }

  // 打开摄像头
  async startRTC() {
    // 连麦观众角色切换为主播，开始推流
    // 设置视频分辨率等参数
    this.localStream_.setVideoProfile({
      width: this.vueInstance.viedoParams.webVideoWidth,
      height: this.vueInstance.viedoParams.webVideoHeight,
      frameRate: this.vueInstance.viedoParams.webVideoFramerate,
      bitrate: this.vueInstance.viedoParams.webVideoBitrate /* kpbs */
    });
    // 避免重复开摄像头
    this.stopPush();
  }

  // 设置本地流
  async setLocalVideo() {
    if (!this.isJoined_) {
      console.warn('请先加入房间');
      return;
    }
    if (this.isPublished_) {
      console.warn('您已经发布过了');
      return;
    }
    try {
      this.localStream_.initialize().catch(error => {
        this.vueInstance.$message({
          message: '打开设备失败,请检查您的设备!',
          type: 'error'
        });
        console.error('failed initialize localStream ' + error);
      }).then(() => {

        // 本地流在主播放器上播放,并且插入到一个关联的box中
        var localVideoWrapEl = document.getElementById('ask');
        this.localStream_.play(localVideoWrapEl, {
          muted: true
        });
        // 主播直接推流
        if (this.role == 'anchor') {
          this.publish();
        }
      }).catch(error => {
        this.vueInstance.$message({
          message: '麦克风打开失败!',
          type: 'error'
        });
      });
    } catch (e) {
      this.isPublished_ = false;
    }
    this.isPublished_ = true;
  }

  // 发布本地流
  async publish() {
    this.client_ && this.client_.publish(this.localStream_).then(() => {
      console.log('本地流发布成功');
      this.isPublished_ = true;
      // 手动将麦克风打开
      this.unmuteLocalAudio();
    }).catch(error => {
      console.log('本地流发布失败');
      this.isPublished_ = false;
      this.vueInstance.reloadfn();
    });
  }

  /**
   * 为避免重复推流，先结束当前推流
   */
  async stopPush() {
    if (this.localStream_ && this.isPublished_ && this.isJoined_) {
        this.client_.unpublish(this.localStream_).then(() => {
          this.isPublished_ = false;
          this.localStream_.stop();
          this.setLocalVideo();
        });
    } else {
      this.setLocalVideo();
    }
  }

  // 退出
  async leave() {
    if (!this.isJoined_) {
      console.warn('leave() - please join() firstly');
      return;
    }
    // 如果是正在发布流，就先停止流
    await this.unpublish();

    // 离开房间
    await this.client_.leave();

    if (this.localStream_) {
      this.muteLocalAudio();
      this.localStream_.stop();
      this.localStream_.close();
      this.localStream_ = null;
    }
    this.isJoined_ = false;
  }

  // 退出本地流
  async unpublish() {
    if (!this.isJoined_) {
      console.warn('unpublish() - please join() firstly');
      return;
    }
    if (!this.isPublished_) {
      console.warn('RtcClient.unpublish() called but not published yet');
      return;
    }

    await this.client_.unpublish(this.localStream_);
    this.isPublished_ = false;
  }

  // 禁用音频轨道
  // 对于本地流，调用该方法会停止发送音频，远端会触发 Client.on('mute-audio') 事件。
  // 对于远端流，调用该方法会停止播放音频，但是仍然接收音频数据。
  muteLocalAudio() {
    console.log('--this.localStream_', this.localStream_);
    const params = {
      roomID: this.roomId_, // 房间id
      viewslist: this.viewslist, // 当前房间用户列表
      TRTCType: 'mute', // trtc 实时通讯状态数据类型 1. error , 2.network-quality  3. AudioStats
      TRTCData: {muteLocalAudio: '静音' }, // trtc 实时通讯状态数据
    };
    _VM.$sendBuriedData({
      action: 'TRTC',
      component_tag: 'TRTC#0',
      web_data: params
    });
    this.localStream_.muteAudio();
  }

  // 启用音频轨道
  // 对于本地流，调用该方法会触发远端 Client.on('unmute-audio') 事件。
  // 音频轨道默认是开启的，若你调用 muteAudio() 后可用该方法重新启用音频。
  unmuteLocalAudio() {
    const params = {
      roomID: this.roomId_, // 房间id
      viewslist: this.viewslist, // 当前房间用户列表
      TRTCType: 'unmute', // trtc 实时通讯状态数据类型 1. error , 2.network-quality  3. AudioStats
      TRTCData: {muteLocalAudio: '取消静音' }, // trtc 实时通讯状态数据
    };
    _VM.$sendBuriedData({
      action: 'TRTC',
      component_tag: 'TRTC#0',
      web_data: params
    });
    this.localStream_.unmuteAudio();
  }

  // 禁用视频轨道
  // 对于本地流，调用该方法会停止发送视频，远端会触发 Client.on('mute-video') 事件。
  // 如果视频是从摄像头采集，此时摄像头灯仍然是亮着的。若想完全禁用视频轨道(即关闭摄像头) ，
  // 可以使用 removeTrack() 删除视频轨道然后调用 MediaStreamTrack.stop() 关闭视频轨道（关闭摄像头）。
  // 对于远端流，调用该方法会停止播放视频，但是仍然接收视频数据.
  muteLocalVideo() {
    this.localStream_.muteVideo();
  }

  // 恢复播放音视频
  // 在某些版本浏览器上移动传入 play() 的 div 容器可能会导致音视频播放器进入 ‘PAUSED’ 状态，此时 需要调用该接口恢复播放。
  // 由于浏览器自动播放策略的限制，在 play() 返回 PLAY_NOT_ALLOWED 错误后需要引导用户通过手势 调用该接口恢复播放
  resumeStreams() {
    this.localStream_.resume();
    for (const stream of this.remoteStreams_) {
      stream.resume();
    }
  }

  // client的一些事件监听
  handleEvents() {
    // 报错
    this.client_.on('error', err => {
      console.log('client 报错了--------------------------------------------------------------');
      console.log(err);
      // alert(err);
      window.onbeforeunload = null;
      location.reload();
    });

    this.client_.on('network-quality', event => {
      console.log('--network-quality', event);
      const params = {
        roomID: this.roomId_, // 房间id
        viewslist: this.viewslist, // 当前房间用户列表
        TRTCType: 'network-quality', // trtc 实时通讯状态数据类型 1. error , 2.network-quality  3. AudioStats
        TRTCData: event, // trtc 实时通讯状态数据
      };
      _VM.$sendBuriedData({
        action: 'TRTC',
        component_tag: 'TRTC#0',
        web_data: params
      });
      this.client_.getLocalAudioStats().then(stats => {
        const params = {
          roomID: this.roomId_, // 房间id
          viewslist: this.viewslist, // 当前房间用户列表
          TRTCType: 'AudioStats_local', // trtc 实时通讯状态数据类型 1. error , 2.network-quality  3. AudioStats
          TRTCData: stats, // trtc 实时通讯状态数据
        };
        _VM.$sendBuriedData({
          action: 'TRTC',
          component_tag: 'TRTC#0',
          web_data: params
        });
      });
      this.client_.getRemoteAudioStats().then(stats => {
        const params = {
          roomID: this.roomId_, // 房间id
          viewslist: this.viewslist, // 当前房间用户列表
          TRTCType: 'AudioStats_remote', // trtc 实时通讯状态数据类型 1. error , 2.network-quality  3. AudioStats
          TRTCData: stats, // trtc 实时通讯状态数据
        };
        console.log('-getRemoteAudioStats', params);
        _VM.$sendBuriedData({
          action: 'TRTC',
          component_tag: 'TRTC#0',
          web_data: params
        });
      });

    });

    // 房间被解散了
    this.client_.on('client-banned', err => {
      console.log('房间被解散了');
    });

    // 当一个远程同伴（必须推流）进入房间时触发
    this.client_.on('peer-join', evt => {
      const userId = evt.userId;
      console.log('有远程同伴进入房间：', userId);
    });

    // 当远处的同伴离开房间时触发(删减好友列表)
    this.client_.on('peer-leave', evt => {
      const userId = evt.userId;
      console.log('有远程同伴离开房间：' + userId);
      this.removeUserList(userId);
    });

    // 在添加远程流时触发
    this.client_.on('stream-added', evt => {
      const remoteStream = evt.stream;
      // 获取流的StreamId
      const id = remoteStream.getId();
      // 获取UserId
      const userId = remoteStream.getUserId();
      this.members_.set(userId, remoteStream);
      this.inmembers_.set(userId, remoteStream);
      console.log(`remote stream added: [${userId}] ID: ${id} type: ${remoteStream.getType()}`);
      // 我们订阅远端的流
      console.log('subscribe to this remote stream');
      this.client_.subscribe(remoteStream);
    });

    // 在订阅远程流时触发
    this.client_.on('stream-subscribed', evt => {
      const remoteStream = evt.stream;
      const id = remoteStream.getId();
      const uid = remoteStream.userId_;
      this.remoteStreams_.push(remoteStream);
      remoteStream.on('player-state-changed', event => {
        console.log(`${event.type} player is ${event.state}`);
        // 远端流是播放还是暂停状态（显示按钮等画面不同）
        if (event.type == 'video' && event.state == 'STOPPED') {
          console.log(`${uid}----------远端流为停止`);
          this.changeView(uid, 'mask', true);
        }
        if (event.type == 'video' && event.state == 'PAUSED') {
          console.log(`${uid}----------远端流为暂停`);
          this.changeView(uid, 'mask', true);
        }
        if (event.type == 'video' && event.state == 'PLAYING') {
          console.log(`${uid}----------远端流为播放`);
          this.changeView(uid, 'mask', false);
        }
      });

        // 避免重复加载
        for (let i = 0; i < this.viewslist.length; i++) {
          if (this.viewslist[i] && uid == this.viewslist[i].userId) {
            return;
          }
        }
        const isMask = false;

        // this.viewslist.push({ id: id, userId: uid, nick: uid, mask: isMask, vioce: true })
        this.add(id, uid, isMask);
        this.vueInstance.addNewMember(uid);

        setTimeout(() => {
          //  避免其他乱入视频
          const index = this.viewslist.findIndex((item => {
            if (item && item.userId) {
              return item.userId == uid;
            } else {
              return -1;
            }

          }));
          if (index < 0) {
            return;
          }

          // 播放视频
          remoteStream.play(id);
          if (!remoteStream.hasVideo()) {
            this.changeView(id, 'mask', true);
          }
          if (!remoteStream.hasAudio()) {
            this.changeView(id, 'vioce', false);
          }
        }, 1000);

    });

    // 当远程流被移除时触发
    this.client_.on('stream-removed', evt => {
      const remoteStream = evt.stream;
      const id = remoteStream.getId();
      const uid = remoteStream.userId_;
      console.log(`${uid}------------远程流被移除时触发`);
      // 停止播放并删除相应<video>标签
      remoteStream.stop();
      this.inmembers_.delete(uid);
      this.remoteStreams_ = this.remoteStreams_.filter(stream => {
        return stream.getId() !== id;
      });
      this.removeUserList(uid);
    });

    // 流更新
    this.client_.on('stream-updated', evt => {
      console.log('=========流更新========stream-updated===================');
      console.log(evt);
      const remoteStream = evt.stream;
      const uid = this.getUidByStreamId(remoteStream.getId());
      // remoteStream.hasVideo()   // 是否有视频轨道
      // remoteStream.hasAudio()   //是否有音轨道
      // remoteStream.getType()    // 主要用于判断一个远端流是主音视频流还是辅路视频流，辅路视频流通常是一个屏幕分享流。
      console.log('remoteStream ID: ' + remoteStream.getId() + ' was updated hasAudio: ' +
        remoteStream.hasAudio() + ' hasVideo: ' + remoteStream.hasVideo());
    });

    // 关闭音轨道
    this.client_.on('mute-audio', evt => {
      this.changeView(evt.userId, 'vioce', false);
      console.log(evt.userId + '关闭麦克风============================================');
    });

    // 打开音轨道
    this.client_.on('unmute-audio', evt => {
      this.changeView(evt.userId, 'vioce', true);
      if (evt.type == 'audio' && evt.state == 'PLAYING' && this.vueInstance.type == 1) {
        this.changeView(evt.userId, 'mask', true);
      }
    });

    // 关闭视频轨道
    this.client_.on('mute-video', evt => {
      console.log(evt.userId + '关闭 video==============================================');
      this.changeView(evt.userId, 'mask', true);
    });

    //  打开视频轨道
    this.client_.on('unmute-video', evt => {
      console.log(evt.userId + '打开 video=============================================');
      if (this.members_.get(evt.userId)) {
        this.changeView(evt.userId, 'mask', false);
      }

    });
  }

  getUidByStreamId(streamId) {
    for (const [uid, stream] of this.members_) {
      if (stream.getId() == streamId) {
        return uid;
      }
    }
  }

  // 移除视频数组
  removeUserList(userId) {
    for(let i = 0; i < this.viewslist.length; i++) {
      if (this.viewslist[i] && this.viewslist[i].userId == userId) {
        this.viewslist[i] = null;
      }
    }
    this.vueInstance.removeMember(userId);
  }
  // 改变视频数组属性
  changeView(id, attr, val) {
    for (let i = 0; i < this.viewslist.length; i++) {
      if (this.viewslist[i] && (this.viewslist[i].userId == id || this.viewslist[i].id == id)) {
        this.viewslist[i][attr] = val;
      }
    }
  }

  add(id, uid, isMask) {
    this.vueInstance.memberList.forEach((ele, index) => {
      if (ele.liveUserId == uid) {
        this.viewslist[index] = { id: id, userId: uid, nick: uid, mask: isMask, vioce: true };
      }
    });
  }
}

export default RtcClient;
