<!-- eslint-disable vue/no-v-html -->
<template>
  <div class="voice-matrix-preview" :style="[getAreaStyle(), getComponentStyle()]">
    <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />

    <div class="main">
      <div class="voice-matrix-audio">
        <div v-show="hasSelectedCell" class="audio-simple">
          <div
            class="audio-simple-image icon-mask"
            :style="{
              backgroundColor: data.unified_attrib?.topic_color,
              maskImage: playing
                ? `url(${require(`@/assets/voice_matrix/icon-voice-play-blue.png`)})`
                : `url(${require(`@/assets/voice_matrix/icon-voice.png`)})`,
            }"
            @click="playAudio"
          ></div>
          <span
            :class="['Repeat-16', 'audio-simple-repeat', isRepeat ? '' : 'disabled']"
            @click="isRepeat = !isRepeat"
          ></span>
        </div>
        <AudioLine
          v-show="!hasSelectedCell"
          ref="audioLine"
          audio-id="voiceMatrixAudio"
          :mp3="mp3Url"
          :get-cur-time="getCurTime"
          :stop-audio="stopAudio"
          :mp3-source="mp3Source"
          :audio-data="data"
          :attrib="data.unified_attrib"
          @handleChangeStopAudio="handleChangeStopAudio"
          @playChange="playChange"
        />
      </div>
      <!-- 语音矩阵 -->
      <div
        class="voice-matrix-container"
        :style="{ height: isEnable(data.property.is_enable_record) ? 'calc(100% - 80px)' : 'auto' }"
      >
        <div
          v-if="data.option_list.length > 0"
          class="matrix"
          :style="{
            'grid-template': `36px repeat(${data.option_list.length}, auto) minmax(36px, 1fr) / 36px repeat(${data.option_list[0].length}, auto) minmax(36px, 1fr)`,
          }"
          @mouseleave="clearSelectCell"
        >
          <!-- 顶部单元格 -->
          <div class="matrix-top" @mouseenter="clearSelectCell"></div>
          <template v-for="(row, i) in data.option_list[0]">
            <div
              :key="`top-${i}`"
              :class="[
                'matrix-top',
                isEnable(data.property.is_enable_column_play) &&
                (selectColumn === i || (selectedLine.type === 'column' && selectedLine.index === i))
                  ? 'read'
                  : '',
              ]"
              @mouseenter="checkboxMouseenter(selectColumn === i, 'column')"
            >
              <span
                v-if="row.type !== 'connection' && isEnable(data.property.is_enable_column_play)"
                v-show="selectColumn === i || (selectedLine.type === 'column' && selectedLine.index === i)"
                :class="[
                  `matrix-checkbox-row-${themeColor}`,
                  selectedLine.type === 'column' && selectedLine.index === i ? 'active' : '',
                ]"
                @click="selectRowOrColumn(i, 'column')"
              ></span>
            </div>
          </template>
          <div class="matrix-top" @mouseenter="clearSelectCell"></div>
          <!-- 主矩阵 -->
          <template v-for="(row, i) in data.option_list">
            <div
              :key="`start-${i}`"
              :class="[
                'column-wrapper',
                isEnable(data.property.is_enable_row_play) &&
                (selectRow === i || (selectedLine.type === 'row' && selectedLine.index === i))
                  ? 'read'
                  : '',
              ]"
              @mouseenter="checkboxMouseenter(selectRow === i, 'row')"
            >
              <span
                v-if="isEnable(data.property.is_enable_row_play)"
                v-show="selectRow === i || (selectedLine.type === 'row' && selectedLine.index === i)"
                :class="[
                  `matrix-checkbox-column-${themeColor}`,
                  selectedLine.type === 'row' && selectedLine.index === i ? 'active' : '',
                ]"
                @click="selectRowOrColumn(i, 'row')"
              ></span>
            </div>
            <!-- 单元格 -->
            <template v-for="(column, j) in row">
              <div
                :key="`wrapper-${i}-${j}`"
                :class="[
                  'column-wrapper',
                  (isEnable(data.property.is_enable_row_play) && selectRow === i) ||
                  (isEnable(data.property.is_enable_column_play) && selectColumn === j) ||
                  (isEnable(data.property.is_enable_column_play) &&
                    selectedLine.type === 'column' &&
                    selectedLine.index === j) ||
                  (isEnable(data.property.is_enable_row_play) &&
                    selectedLine.type === 'row' &&
                    selectedLine.index === i)
                    ? 'read'
                    : '',
                ]"
                @mouseenter="matrixCellMouseenter(i, j, column.type)"
              >
                <!-- 文本 -->
                <div
                  :key="`column-${i}-${j}`"
                  :class="[
                    column.content.length === 0 ? 'space' : `column-${themeColor}`,
                    (selectCell.row === i && selectCell.column === j) ||
                    (selectedLine.type === 'column' && selectedLine.index === j) ||
                    (selectedLine.type === 'row' && selectedLine.index === i)
                      ? 'selected'
                      : '',
                    playing &&
                    column.lrc_data.begin_time / 1000 <= curTime &&
                    (curTime < column.lrc_data.end_time / 1000 || column.lrc_data.end_time === -1)
                      ? 'playing'
                      : '',
                    column.isTitle ? 'title' : '',
                  ]"
                  @click="matrixCellClick(i, j)"
                >
                  <span
                    class="content rich-text"
                    :style="{ textAlign: data.property.align }"
                    v-html="convertText(sanitizeHTML(column.content))"
                  ></span>

                  <div v-if="showLang" class="lang">
                    {{ column.multilingual.find((item) => item.type === getLang())?.translation }}
                  </div>
                </div>
              </div>
            </template>

            <div
              :key="`end-${i}`"
              :class="[
                isEnable(data.property.is_enable_row_play) &&
                (selectRow === i || (selectedLine.type === 'row' && selectedLine.index === i))
                  ? 'read'
                  : '',
              ]"
              @mouseenter="clearSelectCell"
            ></div>
          </template>
          <!-- 底部格子 -->
          <div class="matrix-bottom" @mouseenter="clearSelectCell"></div>
          <template v-for="(row, i) in data.option_list[0]">
            <div
              :key="`bottom-${i}`"
              :class="[
                'matrix-bottom',
                isEnable(data.property.is_enable_column_play) &&
                (selectColumn === i || (selectedLine.type === 'column' && selectedLine.index === i))
                  ? 'read'
                  : '',
              ]"
              @mouseenter="clearSelectCell"
            ></div>
          </template>
          <div class="matrix-bottom" @mouseenter="clearSelectCell"></div>
        </div>
      </div>
      <!-- 录音 -->
      <div v-if="isEnable(data.property.is_enable_record)" class="voice-luyin">
        <SoundRecord
          ref="luyin"
          type="promax"
          class="luyin-box"
          :answer-record-list="data.record_list"
          :attrib="data.unified_attrib"
          @getWavblob="getWavblob"
          @getSelectData="getSelectData"
          @handleParentPlay="pauseOtherAudio"
          @sentPause="sentPause"
          @handleWav="handleWav"
        />
        <AudioCompare
          :style="{ flex: 1 }"
          :theme-color="themeColor"
          :wavblob="wavblob"
          type="full"
          :attrib="data.unified_attrib"
          :url="mp3Url"
          :is-record="isRecord"
          :sent-pause="sentPause"
          :matrix-select-lrc="matrixSelectLrc"
          :get-cur-time="getCurTime"
          :cur-time="curTime"
          :handle-change-stop-audio="handleChangeStopAudio"
          @playing="playChange"
        />
      </div>
    </div>

    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" />
    <AnswerAnalysis
      :visible.sync="visibleAnswerAnalysis"
      :answer-list="data.answer_list"
      :analysis-list="data.analysis_list"
      @closeAnswerAnalysis="closeAnswerAnalysis"
    />
  </div>
</template>

<script>
import { getVoiceMatrixData } from '@/views/book/courseware/data/voiceMatrix';
import { getRandomNumber } from '@/utils/index.js';

import PreviewMixin from '../common/PreviewMixin';
import Bus from './components/Bus.js';
import SoundRecord from '../../common/SoundRecord.vue';
import AudioCompare from './components/AudioCompareMatrix.vue';
import AudioLine from './components/AudioLine.vue';

export default {
  name: 'VoiceMatrixPreview',
  components: {
    SoundRecord,
    AudioCompare,
    AudioLine,
  },
  mixins: [PreviewMixin],
  data() {
    return {
      data: getVoiceMatrixData(),
      cid: getRandomNumber(),
      themeColor: 'red',
      curTime: 0,
      playing: false,
      stopAudio: true,
      unWatch: null,
      lrcArray: [],
      fileName: '',
      // 底色行、列
      selectRow: -1,
      selectColumn: -1,
      // 行、列选中
      selectedLine: {
        type: '',
        index: 0,
      },
      // 点击选中
      selectCell: {
        row: -1,
        column: -1,
      },
      isRepeat: false,
      // 跟读所需属性
      wavblob: null,
      isRecord: false,
      matrixSelectLrc: null,
    };
  },
  computed: {
    hasSelectedCell() {
      const { type, index } = this.selectedLine;
      const { row, column } = this.selectCell;
      return (type.length > 0 && index >= 0) || (row >= 0 && column >= 0);
    },
    mp3Url() {
      const audioData = this.data.audio_data;
      return audioData.url.match(/^\[FID##/) ? audioData.temporary_url : audioData.url;
    },
    mp3Source() {
      const audioData = this.data.audio_data;
      return 'source' in audioData ? audioData.source : '';
    },
    mp3Duration() {
      return this.data.audio_data.media_duration * 1000;
    },
    selectData() {
      const { type, index } = this.selectedLine;
      const { row, column } = this.selectCell;
      return {
        type: type.length > 0 && index >= 0 ? type : 'cell',
        index,
        row,
        column,
      };
    },
  },
  watch: {
    hasSelectedCell() {
      this.handleParentPlay();
    },
    isShowRightAnswer(val) {
      if (!val) return;
      this.handleWav(this.answer.record_list);
      if (this.answer.record_list.length > 0) {
        this.getWavblob(this.answer.record_list[0].wavData);
      }
    },
    'data.record_list'(val) {
      this.answer.record_list = val;
    },
  },
  created() {
    Bus.$on('audioPause', (id) => {
      if (this.cid === id) return;
      if (this.$refs.luyin?.microphoneStatus) this.$refs.luyin.microphone();
      this.handleParentPlay();
    });
    if (!('record_list' in this.answer)) {
      this.$set(this.answer, 'record_list', []);
    }
  },
  mounted() {
    document.querySelector('body').addEventListener('click', this.restoreAudioStatus);
  },
  beforeDestroy() {
    document.querySelector('body').removeEventListener('click', this.restoreAudioStatus);
  },
  methods: {
    handleWav(data) {
      this.data.record_list = data;
    },
    // 鼠标移入移出
    matrixCellMouseenter(i, j, type) {
      if (type === 'connection') {
        this.selectRow = -1;
        this.selectColumn = -1;
      } else {
        this.selectRow = i;
        this.selectColumn = j;
      }
    },

    clearSelectCell() {
      this.selectRow = -1;
      this.selectColumn = -1;
    },

    // 单击单元格
    matrixCellClick(row, column) {
      if (this.playing) this.handleParentPlay();
      if (this.unWatch) this.unWatch();
      this.lrcArray = [];
      if (row === this.selectCell.row && column === this.selectCell.column) {
        this.selectCell = { row: -1, column: -1 };
        return;
      }
      this.selectedLine = { type: '', index: -1 };
      this.selectCell = { row, column };
      this.handleChangeTime(this.data.option_list[row][column].lrc_data);
      // 设置录音文件名
      this.setRecordingFileName(row, column);
    },

    setRecordingFileName(row, column) {
      return `录音第${column}列第${row}行`;
    },

    /**
     * 判断 click 点击是否语音矩阵可操作区域
     * @param {PointerEvent} event
     */
    restoreAudioStatus(event) {
      const whitePath = [
        'column-green',
        'column-red',
        'column-brown',
        'matrix-checkbox-column-',
        'matrix-checkbox-row-',
        'audio-simple-image',
        'audio-simple-repeat',
        'luyin-box',
      ];
      const operable = event.composedPath().some((item) => {
        const className = item.className;
        if (!className || typeof className !== 'string') return false;
        return whitePath.some((path) => className.includes(path));
      });
      if (!operable) {
        this.selectedLine = { type: '', index: -1 };
        this.selectCell = { row: -1, column: -1 };
        if (this.playing) this.handleParentPlay();
        if (this.unWatch) this.unWatch();
      }
    },

    checkboxMouseenter(isSelected, type) {
      if (!isSelected) return this.clearSelectCell();
      if (type === 'row') this.selectColumn = -1;
      if (type === 'column') this.selectRow = -1;
    },

    // 选中行、列
    selectRowOrColumn(index, type) {
      this.handleParentPlay();
      this.lrcArray = [];
      this.selectCell = { row: -1, column: -1 };
      if (this.unWatch) this.unWatch();
      if (this.selectedLine.type === type && this.selectedLine.index === index) {
        this.selectedLine = { type: '', index: -1 };
        return;
      }
      this.selectedLine = { type, index };
      let number = index;
      if (type === 'column') {
        this.data.option_list[index].forEach((item, i) => {
          if (i >= index) return;
        });
      }
      this.fileName = `第 ${number + 1} ${type === 'row' ? '行' : '列'}`;
    },

    playAudio() {
      if (!this.hasSelectedCell) return;
      if (this.playing) return this.handleParentPlay();
      if (this.lrcArray.length > 0) return this.$refs.audioLine.PlayAudio();
      if (this.unWatch) this.unWatch();

      this.lrcArray = [];
      const { type, index } = this.selectedLine;

      if (type.length > 0 && index >= 0 && type === 'row') {
        this.data.option_list[index].forEach((item) => {
          const data = this.getLrcData(item);
          if (data) this.lrcArray.push(data);
        });
        if (this.lrcArray.length > 0) this.lrcPlay(this.lrcArray[0], 0);
        return;
      }

      if (type.length > 0 && index >= 0 && type === 'column') {
        this.data.option_list.forEach((item) => {
          const data = this.getLrcData(item[index]);
          if (data) this.lrcArray.push(data);
        });
        if (this.lrcArray.length > 0) this.lrcPlay(this.lrcArray[0], 0);
        return;
      }

      const { row, column } = this.selectCell;
      if (row >= 0 && column >= 0) {
        this.handleChangeTime(this.data.option_list[row][column].lrc_data);
      }
    },

    lrcPlay({ begin_time, end_time }, index) {
      this.handleParentPlay();
      this.$nextTick(() => {
        this.$refs.audioLine.onTimeupdateTime(begin_time / 1000);
        this.$refs.audioLine.PlayAudio();
        if (end_time === -1) return;
        const end = end_time / 1000 - 0.01;
        this.unWatch = this.$watch('curTime', (val) => {
          if (val >= end) {
            if (!this.hasSelectedCell) return this.unWatch();
            this.handleParentPlay();
            this.$refs.audioLine.onTimeupdateTime(end);
            this.unWatch();
            const i = index + 1;
            if (i < this.lrcArray.length) {
              return this.lrcPlay(this.lrcArray[i], i);
            }
            if (this.isRepeat) {
              return this.lrcPlay(this.lrcArray[0], 0);
            }
            this.lrcArray = [];
          }
        });
      });
    },

    playChange(playing) {
      this.playing = playing;
      // 子组件通信，同时只能播放一个音频
      if (playing) Bus.$emit('audioPause', this.cid);
    },

    pauseOtherAudio() {
      Bus.$emit('audioPause', this.cid);
      this.stopAudio = true;
    },

    // 暂停音频播放
    handleParentPlay() {
      this.stopAudio = true;
    },
    // 音频播放时改变布尔值
    handleChangeStopAudio() {
      this.stopAudio = false;
    },

    getCurTime(curTime) {
      this.curTime = curTime;
    },

    getWavblob(wavblob) {
      this.wavblob = wavblob;
    },

    getSelectData({ type, index, row, column }) {
      if (type === '') return;
      const arr = [];
      if (type.length > 0 && index >= 0 && type === 'row') {
        this.data.option_list[index].forEach((item) => {
          const data = this.getLrcData(item);
          if (data) arr.push(data);
        });
        this.matrixSelectLrc = arr;
        return;
      }

      if (type.length > 0 && index >= 0 && type === 'column') {
        this.data.option_list.forEach((item) => {
          const data = this.getLrcData(item[index]);
          if (data) arr.push(data);
        });
        this.matrixSelectLrc = arr;
        return;
      }

      if (type === 'cell' && row >= 0 && column >= 0) {
        const lrcData = this.data.option_list[row][column].lrc_data;
        if (lrcData.end_time === -1) lrcData.end_time = this.mp3Duration;
        this.matrixSelectLrc = [lrcData];
      }
    },

    getLrcData({ content, lrc_data }) {
      if (content.length > 0) {
        if (lrc_data.end_time === -1) {
          return {
            begin_time: lrc_data.begin_time,
            end_time: this.mp3Duration,
            text: lrc_data.text,
          };
        }
        return lrc_data;
      }
      return false;
    },

    sentPause(isRecord) {
      this.isRecord = isRecord;
    },

    handleChangeTime({ begin_time, end_time }) {
      if (this.unWatch) this.unWatch();
      this.handleParentPlay();
      this.$nextTick(() => {
        this.$refs.audioLine.onTimeupdateTime(begin_time / 1000);
        this.$refs.audioLine.PlayAudio();
        // 监听是否已到结束时间，为了选中效果 - 0.01
        if (end_time === -1) return;
        const end = end_time / 1000 - 0.01;
        this.unWatch = this.$watch('curTime', (val) => {
          if (val >= end) {
            this.handleParentPlay();
            this.$refs.audioLine.onTimeupdateTime(end);
            this.unWatch();
            this.unWatch = null;
            if (this.isRepeat) {
              this.handleChangeTime({ begin_time, end_time });
            }
          }
        });
      });
    },
  },
};
</script>

<style lang="scss" scoped>
@use '@/styles/mixin.scss' as *;

$select-color: #1890ff;
$border-color: #e6e6e6;

.voice-matrix-preview {
  @include preview-base;

  .main {
    color: #262626;

    .voice-matrix-audio {
      display: flex;
      height: 42px;
      border: 1px solid $border-color;
      border-radius: 8px 8px 0 0;

      .audio-number {
        padding: 12px 0 0 12px;

        %serial-number,
        .serial-number {
          display: inline-block;
          width: 16px;
          height: 16px;
          font-family: 'robot';
          font-size: 16px;
          line-height: 16px;
          color: #000;
          text-align: center;
          border-radius: 50%;
        }
      }

      .audio-simple {
        display: flex;
        flex-grow: 1;
        align-items: center;
        justify-content: space-between;
        height: 100%;
        line-height: 46px;

        .audio-simple-image {
          width: 24px;
          height: 24px;
          margin-left: 12px;
          cursor: pointer;
        }

        img {
          width: 16px;
          height: 16px;
          margin-left: 12px;
          cursor: pointer;
        }

        .Repeat-16 {
          display: inline-block;
          width: 16px;
          height: 16px;
          margin-right: 12px;
          cursor: pointer;
        }
      }
    }

    // 语音矩阵
    .voice-matrix-container {
      font-size: 16px;
      word-break: break-word;
      background-color: #f5f5f5;
      border-right: 1px solid $border-color;
      border-bottom: 1px solid $border-color;
      border-left: 1px solid $border-color;

      .matrix {
        display: inline-grid;
        width: 100%;
        height: 100%;

        %matrix-checkbox {
          position: relative;
          top: calc(50% - 5px);
          display: block;
          width: 14px;
          height: 14px;
          margin: 0 auto;
          cursor: pointer;
          border: 1.5px solid #b0b0b0;
          border-radius: 4px;

          &.active {
            border-color: $select-color;

            &::after {
              position: absolute;
              left: 4px;
              box-sizing: content-box;
              width: 3px;
              height: 7px;
              content: '';
              border: 1px solid $select-color;
              border-top: 0;
              border-left: 0;
              transition: transform 0.15s ease-in 0.05s;
              transform: rotate(45deg) scaleY(1);
              transform-origin: center;
            }
          }
        }

        .matrix-checkbox-row-,
        .matrix-checkbox-row-red {
          @extend %matrix-checkbox;
        }

        %matrix-checkbox-column,
        .matrix-checkbox-column-,
        .matrix-checkbox-column-red {
          @extend %matrix-checkbox;

          top: calc(50% - 7px);
          right: -2px;
        }

        .read {
          background-color: #eaeaea;
        }

        .highlight-,
        .highlight-red {
          color: $select-color;
        }

        .column-wrapper {
          padding: 4px;

          %column {
            width: 100%;
            height: 100%;
            min-height: 32px;
            cursor: pointer;
            user-select: none;
            background-color: #fff;
            border: 1px solid $border-color;
            border-radius: 4px;
            transition: 0.2s;

            &:hover {
              border-color: #8c8c8c;
            }

            &.selected {
              color: $select-color;
              border-color: $select-color;
            }

            &.playing {
              background-color: rgba(24, 144, 255, 10%);
            }

            &.title {
              background-color: transparent;
              border-color: transparent;
            }

            > span {
              display: inline-block;
              width: 100%;
              padding: 4px 12px;
              line-height: 24px;
            }

            .lang {
              padding: 0 12px 4px;
            }
          }

          %column-red,
          .column-,
          .column-red {
            @extend %column;

            position: relative;

            &::before {
              display: inline-block;
              vertical-align: middle;
              content: '';
            }
          }

          %sentence,
          .sentence-,
          .sentence-red {
            @extend %column;

            display: inline-grid;
            column-gap: 8px;
            justify-content: start;
            justify-items: center;
            padding: 4px 12px;
            line-height: 24px;

            > span {
              padding: 0;
            }

            .pinyin {
              font-family: 'League';
              font-size: 12px;
              line-height: 20px;
              opacity: 0.45;
            }

            .chs {
              font-size: 16px;
              line-height: 24px;
            }
          }

          .connection {
            position: relative;
            top: calc(50% - 1px);
            width: 16px;
            height: 2px;
            margin: 0 -4px;
            background-color: #252525;
            border-radius: 4px;

            &.highlight-bc-,
            &.highlight-bc-red {
              background-color: $select-color;
            }
          }

          // 拼音 + 文字
          %pinyin-english,
          .pinyinEnglish-,
          .pinyinEnglish-red {
            @extend %column;

            .inside-wrapper {
              padding: 4px 12px;

              .pinyin {
                font-family: 'League';
                font-size: 16px;
                line-height: 24px;
              }

              .english {
                font-family: 'robot';
                font-size: 12px;
                line-height: 20px;
                opacity: 0.45;
              }
            }
          }
          %text-brackets,
          .textBrackets-,
          .textBrackets-red {
            @extend %column;

            .brackets-text {
              font-family: 'League';
            }

            .brackets {
              font-size: 16px;
            }
          }
        }
      }

      .matrix-audio {
        width: 228px;
        height: 40px;
        padding: 4px 4px 4px 16px;
        margin: 24px 24px 0 0;
        background-color: #fff;
        border: 1px solid $border-color;
        border-radius: 8px;
      }
    }

    .voice-luyin {
      display: flex;
      align-items: center;
      height: 40px;
      padding: 3px 16px;
      border: 1px solid $border-color;
      border-top-width: 0;
      border-radius: 0 0 8px 8px;

      :deep .record {
        max-width: 280px;
      }
    }
  }
}

.NNPE-tableList-tr-last {
  .voice-matrix {
    padding-bottom: 0;
  }
}
</style>

<style lang="scss">
.voice-matrix {
  &-audio {
    .audioLine {
      border-radius: 8px 8px 0 0 !important;
    }

    .el-slider {
      width: 100% !important;
    }
  }

  .luyin-box {
    .el-select .el-input {
      width: 136px;
    }
  }
}
</style>
