<template>
  <div class="video-communication">
    <div class="part-box-head">
      <div class="part-box-head-left"><h1>通话申请列表</h1></div>
      <div class="part-box-head-right">
        <el-radio-group
          size="small"
          v-model="callStatus"
          @change="getCommunicationList"
        >
          <el-radio-button label="START">待处理</el-radio-button>
          <el-radio-button label="STOP">已处理</el-radio-button>
        </el-radio-group>
        <el-button
          style="vertical-align: top; margin-left: 10px;"
          icon="el-icon-arrow-left"
          @click="goBack"
          >返回</el-button
        >
      </div>
    </div>
    <div class="student-list">
      <el-row :gutter="20">
        <el-col :md="6" :lg="6" :xl="4" v-for="item in students" :key="item.id">
          <div class="student-item">
            <div class="student-cover">
              <img
                :src="item.basePhotoPath"
                :alt="item.examStudentId"
                v-if="item.basePhotoPath"
              />
              <div class="avatar-default" v-else>
                <i class="el-icon-user-solid"></i>
              </div>
            </div>
            <h4 class="student-name">{{ item.examStudentName }}</h4>
            <div v-if="callStatus === 'START'">
              <el-button
                round
                type="success"
                @click="answer(item, 0)"
                :loading="holding"
                >语音通话</el-button
              >
              <br />
              <el-button
                round
                type="primary"
                @click="answer(item, 1)"
                :loading="holding"
                >视频通话</el-button
              >
            </div>
            <div class="student-call-info" v-else>
              <p>
                通话时间段：
                <span>{{ item.startTime }} ~ </span>
                <span>{{ item.endTime }}</span>
              </p>
              <p v-if="item.durationTime">
                持续时长约：{{ item.durationTime }}
              </p>
            </div>
          </div>
        </el-col>
      </el-row>
    </div>

    <div class="part-page">
      <el-pagination
        background
        layout="prev, pager, next,total,sizes,jumper"
        :current-page="current"
        :total="total"
        :page-size.sync="size"
        @size-change="toPage(1)"
        @current-change="toPage"
      >
      </el-pagination>
    </div>

    <!-- 通话弹出层 -->
    <el-dialog
      custom-class="communication-dialog"
      :visible.sync="dialogVisible"
      width="600px"
      :show-close="false"
      :close-on-press-escape="false"
      :close-on-click-modal="false"
      append-to-body
      fullscreen
    >
      <div class="communication-box">
        <div class="communication-host" id="communication-host"></div>
        <div class="communication-guest" id="communication-guest"></div>
        <div class="communication-action">
          <el-button round type="danger" @click="hangup">结束通话</el-button>
        </div>
        <div class="communication-info">
          <!-- <span>当前网络状态良好</span> -->
          <span>持续时长：<second-timer ref="SecondTimer"></second-timer></span>
        </div>
      </div>
      <span slot="footer" class="dialog-footer"> </span>
    </el-dialog>
  </div>
</template>

<script>
import { createClient, createStream } from "@/plugins/trtc";
import {
  communicationList,
  communicationCalling,
  communicationOver,
  getUserMonitorKey,
} from "@/api/invigilation";
import SecondTimer from "../common/SecondTimer";
import { formatDate, timeNumberToText } from "@/utils/utils";

const domEmpty = (dom) => {
  dom.childNodes.forEach((childNode) => {
    dom.removeChild(childNode);
  });
};

export default {
  name: "video-communication",
  components: { SecondTimer },
  data() {
    return {
      examId: this.$route.params.examId,
      callStatus: "START",
      dialogVisible: false,
      holding: false,
      students: [],
      curStudent: {},
      current: 1,
      total: 0,
      size: 100,
      setT: null,
      loopRunning: false,
      userMonitor: {},
      client: null,
      localStream: null,
      isHandup: false,
    };
  },
  mounted() {
    this.loopRunning = true;
    this.getCommunicationList();
  },
  methods: {
    async getCommunicationList() {
      if (this.setT) clearTimeout(this.setT);
      if (!this.loopRunning) return;

      const res = await communicationList({
        examId: this.examId,
        callStatus: this.callStatus,
        pageNumber: this.current,
        pageSize: this.size,
      }).catch(() => {});
      if (res) {
        this.students = res.data.data.records.map((item) => {
          item.durationTime = timeNumberToText(item.endTime - item.startTime);
          item.startTime = formatDate(
            "YYYY-MM-DD HH:mm:ss",
            new Date(item.startTime)
          );
          item.endTime = formatDate(
            "YYYY-MM-DD HH:mm:ss",
            new Date(item.endTime)
          );
          return item;
        });
        this.total = res.data.data.total;
      }
      // 当前页没有数据，同时当前页不是第一页，则自动跳到前一页。
      if (!this.students.length && this.current > 1) {
        this.current--;
        this.getCommunicationList();
      } else {
        this.setT = setTimeout(() => {
          this.getCommunicationList();
        }, 5000);
      }
    },
    toPage(page) {
      this.current = page;
      this.getCommunicationList();
    },
    notifyError(content) {
      this.$notify({
        type: "error",
        message: content,
      });
    },
    async initClient(examRecordId) {
      const res = await getUserMonitorKey(examRecordId);
      this.userMonitor = res.data.data;
      this.client = createClient({
        mode: "live",
        sdkAppId: this.userMonitor.appId,
        userId: this.userMonitor.monitorUserId,
        userSig: this.userMonitor.monitorUserSig,
      });
    },
    async getLocalMedia(isVideo) {
      const localStream = createStream({
        userId: this.userMonitor.monitorUserId,
        audio: true,
        video: isVideo,
      });
      const errorTips = {
        NotFoundError: "找不到硬件设备，请确保硬件设备已经正常插入。",
        NotAllowedError: "不授权摄像头/麦克风访问无法进行音视频通话。",
        NotReadableError:
          "暂时无法访问摄像头/麦克风，请确保当前没有其他应用请求访问摄像头/麦克风，并重试。",
        OverConstrainedError: "设备异常",
        AbortError: "设备异常",
      };

      let initLocalStreamResult = true;
      await localStream.initialize().catch((error) => {
        console.log(errorTips[error.name]);
        this.notifyError(errorTips[error.name] || "未知错误");
        initLocalStreamResult = false;
        localStream.close();
      });
      return initLocalStreamResult && localStream;
    },
    async answer(student, isVideo) {
      if (this.holding) return;
      this.holding = true;

      this.curStudent = student;
      await this.initClient(student.examRecordId).catch(() => {});
      if (!this.client) {
        this.holding = false;
        return;
      }
      this.localStream = await this.getLocalMedia(isVideo);
      if (!this.localStream) {
        this.holding = false;
        return;
      }

      this.dialogVisible = true;
      this.holding = false;
      // 添加远程用户视频发布监听
      this.client.on("stream-added", (event) => {
        console.log(event);
        console.log(event.stream.getUserId(), student.sourceUserId);
        const remoteStream = event.stream;
        if (remoteStream.getUserId() !== student.sourceUserId) return;
        if (remoteStream.getType() !== "main") return;
        console.log(`有效视频${remoteStream.getUserId()}，准备订阅`);

        this.client
          .subscribe(remoteStream, { audio: true, video: true })
          .catch((error) => {
            console.log(`${remoteStream.getUserId()}视频订阅失败！`, error);
            this.notifyError("学生视频获取失败！");
          });
      });
      this.client.on("stream-subscribed", (event) => {
        const remoteStream = event.stream;
        console.log(event);
        console.log(`${remoteStream.getUserId()}视频已订阅！`);
        if (!this.$refs.SecondTimer.recoding) this.$refs.SecondTimer.start();
        domEmpty(document.getElementById("communication-host"));
        remoteStream.play("communication-host", { objectFit: "contain" });
      });
      this.client.on("stream-removed", (event) => {
        // 监考端手动挂断时也会触发这个事件
        const remoteStream = event.stream;
        if (
          remoteStream.getUserId() !== student.sourceUserId ||
          remoteStream.getType() !== "main" ||
          this.isHandup
        )
          return;
        console.log(event);
        console.log(`${remoteStream.getUserId()}已退出房间！`);
        this.notifyError("对方已挂断！");
        this.hangup();
      });

      // 加入房间
      let roomJoinResult = true;
      await this.client
        .join({
          roomId: this.userMonitor.monitorKey,
          role: "audience",
          // role: "anchor"
        })
        .catch((error) => {
          roomJoinResult = false;
          console.log("加入房间失败！", error);
          this.notifyError("接通通信失败！");
        });
      if (!roomJoinResult) return;
      console.log("加入房间成功！");

      // 切换角色，连麦互动
      let switchResult = true;
      await this.client.switchRole("anchor").catch((error) => {
        console.log("切换角色失败！", error);
        this.notifyError("角色错误！");
        switchResult = false;
      });
      if (!switchResult) return;

      // 发布本地视频
      let publishStreamResult = true;
      this.client.publish(this.localStream).catch((error) => {
        console.log("发布本地视频失败！", error);
        this.notifyError("本地音视频推送失败！");
        publishStreamResult = false;
      });
      if (!publishStreamResult) return;
      console.log("发布本地音视频成功！");

      // 播放本地视频
      this.localStream.play("communication-guest", { muted: true });

      // 更改学生的通话申请状态
      await communicationCalling({
        recordId: student.examRecordId,
        source: student.source,
      });
      this.isHandup = false;
    },
    async hangup() {
      if (this.isHandup) return;
      this.isHandup = true;
      this.$refs.SecondTimer.end();
      // 结束学生的通话
      await communicationOver({
        recordId: this.curStudent.examRecordId,
        source: this.curStudent.source,
      }).catch(() => {
        console.log("结束通话状态异常！");
      });
      this.curStudent = {};

      // 取消发布本地视频
      await this.client.unpublish(this.localStream).catch((error) => {
        console.log("取消发布本地视频失败！", error);
      });

      this.localStream.close();
      this.localStream = null;

      let result = true;
      await this.client.leave().catch((error) => {
        console.log("离开房间失败！", error);
        this.notifyError("操作异常，请重新尝试！");
        result = false;
      });
      if (!result) return;

      this.client.off("*");
      this.client = null;
      this.userMonitor = {};
      this.dialogVisible = false;
    },
    goBack() {
      window.history.go(-1);
    },
  },
  beforeDestroy() {
    this.loopRunning = false;
    if (this.setT) clearTimeout(this.setT);
    if (this.client) {
      this.client.leave();
      this.client.off("*");
    }
  },
};
</script>

<style lang="scss" scoped>
.student-list {
  .student-item {
    padding: 20px;
    background: #fff;
    border-radius: 10px;
    text-align: center;
    margin-bottom: 20px;
    .el-button {
      margin-bottom: 12px;
    }
  }
  .student-cover {
    height: 200px;
    border-radius: 6px;
    overflow: hidden;
    img {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }
  .student-name {
    margin: 20px 0;
    font-size: 18px;
    line-height: 25px;
    color: #202b4b;
  }
  .student-call-info {
    p {
      margin: 0;
      text-align: left;
    }
  }
}
</style>
