<!-- eslint-disable vue/no-v-html -->
<template>
  <ModuleBase ref="base" :type="data.type">
    <template #content>
      <!-- eslint-disable max-len -->
      <div class="fill-wrapper">
        <RichText
          v-if="property.isGetContent"
          ref="richText"
          v-model="data.content"
          :is-fill="true"
          toolbar="fontselect fontsizeselect forecolor backcolor | lineheight paragraphSpacing underline | bold italic strikethrough alignleft aligncenter alignright bullist numlist dotEmphasis"
          :wordlimit-num="false"
          :font-size="data?.unified_attrib?.font_size"
          :font-family="data?.unified_attrib?.font"
          :font-color="data?.unified_attrib?.text_color"
          @handleRichTextBlur="identifyText"
        />
        <div v-if="data.property.fill_type === fillTypeList[1].value" class="select-vocabulary">
          <h5 class="title">选词列表：</h5>
          <el-button size="mini" @click="openAddWord">添加词汇</el-button>
          <ul class="word-list">
            <li v-for="(item, index) in data.word_list" :key="item.mark" class="word-item">
              <span v-html="sanitizeHTML(item.content)"></span>
              <el-button type="text" size="mini" class="delete-word" @click="removeWord(index)">
                <SvgIcon icon-class="delete-black" size="12" />
              </el-button>
            </li>
          </ul>
        </div>

        <span class="tips">在需要加空的内容处插入 3 个或以上的下划线“_”。</span>
        <div v-if="data.audio_file_id">
          <SoundRecord :wav-blob.sync="data.audio_file_id" />
        </div>
        <template v-else>
          <div :class="['upload-audio-play']">
            <UploadAudio
              v-if="data.property.audio_generation_method === 'upload'"
              :file-id="data.audio_file_id"
              :show-upload="!data.audio_file_id"
              @upload="uploads"
              @deleteFile="deleteFiles"
            />
            <div v-else-if="data.property.audio_generation_method === 'auto'" class="auto-matic" @click="handleMatic">
              <SvgIcon icon-class="voiceprint-line" class="record" />
              <span class="auto-btn">{{ data.audio_file_id ? '已生成' : '生成音频' }}</span
              >{{ data.audio_file_id ? '成功' : '' }}
            </div>
            <SoundRecord v-else :wav-blob.sync="data.audio_file_id" />
          </div>
        </template>

        <div>
          <el-button @click="identifyText">识别</el-button>
          <el-button @click="openMultilingual">多语言</el-button>
        </div>

        <div v-if="data.answer.answer_list.length > 0" class="title">答案：</div>
        <div class="correct-answer">
          <el-input
            v-for="(item, i) in data.answer.answer_list.filter(({ type }) => type === 'any_one')"
            :key="item.mark"
            v-model="item.value"
            placeholder="多个答案可用‘/’分割"
            @blur="handleTone(item.value, i)"
          >
            <span slot="prefix">{{ i + 1 }}.</span>
          </el-input>
        </div>
      </div>

      <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">拼音效果</el-divider>
      <template v-if="isEnable(data.property.view_pinyin)">
        <div v-for="(item, i) in data.model_essay" :key="i" class="pinyin-text-list">
          <template v-for="(li, j) in item">
            <PinyinText
              :key="`${i}-${j}`"
              ref="PinyinText"
              :paragraph-list="li.paragraph_list"
              :rich-text-list="li.rich_text_list"
              :pinyin-position="data.property.pinyin_position"
              @fillCorrectPinyin="fillCorrectPinyin($event, i, j, 'model_essay')"
            />
          </template>
        </div>
      </template>

      <MultilingualFill
        :visible.sync="multilingualVisible"
        :text="data.content"
        :translations="data.multilingual"
        @SubmitTranslation="handleMultilingualTranslation"
      />
      <AnswerAnalysisList
        v-if="data.answer_list?.length > 0 || data.analysis_list?.length > 0"
        :answer-list="data.answer_list"
        :analysis-list="data.analysis_list"
        :unified-attrib="data.unified_attrib"
        @updateAnswerAnalysisFileList="updateAnswerAnalysisFileList"
        @deleteAnswerAnalysis="deleteAnswerAnalysis"
      />
      <AddWord :visible.sync="visibleWord" @add-word="addWord" />
    </template>
  </ModuleBase>
</template>

<script>
import ModuleMixin from '../../common/ModuleMixin';
import SoundRecord from '@/views/book/courseware/create/components/question/fill/components/SoundRecord.vue';
import UploadAudio from '@/views/book/courseware/create/components/question/fill/components/UploadAudio.vue';
import PinyinText from '@/components/PinyinText.vue';
import AddWord from './components/AddWord.vue';

import { getFillData, arrangeTypeList, fillTypeList } from '@/views/book/courseware/data/fill';
import { addTone, handleToneValue } from '@/views/book/courseware/data/common';
import { getRandomNumber } from '@/utils';
import { TextToAudioFile } from '@/api/app';
import { sanitizeHTML } from '@/utils/common';

export default {
  name: 'FillPage',
  components: {
    SoundRecord,
    UploadAudio,
    PinyinText,
    AddWord,
  },
  mixins: [ModuleMixin],
  data() {
    return {
      data: getFillData(),
      fillTypeList,
      sanitizeHTML,
      visibleWord: false,
    };
  },
  watch: {
    'data.property.arrange_type': 'handleMindMap',
    'data.property.fill_font': 'handleMindMap',
    'data.property': {
      handler() {
        this.handleViewPinyin();
      },
      deep: true,
    },
  },
  methods: {
    // 识别文本
    identifyText() {
      this.data.answer.answer_list = [];
      const content = this.data.content || '';

      // 使用 class 为 rich-fill 的 span 以及连续 3 个及以上下划线作为分割符
      if (!content || !content.match(/<span[^>]*class="[^"]*rich-fill[^"]*"[^>]*>(.*?)<\/span>|_{3,}/gi)) {
        this.data.model_essay = [
          [
            {
              content,
              type: 'text',
              paragraph_list: [],
              paragraph_list_parameter: { text: '', pinyin_proofread_word_list: [] },
            },
          ],
        ];
        return;
      }

      const splitSource = content.split('\n').map((item) => {
        // rich-fill 和 ___ 均转为统一占位符，交给 splitRichText 处理
        return this.splitRichText(
          item.replace(/<span[^>]*class="[^"]*rich-fill[^"]*"[^>]*>.*?<\/span>|_{3,}/gi, '###$&###'),
        );
      });

      this.data.model_essay = splitSource;

      this.handleViewPinyin();
    },
    /**
     * 分割富文本
     * @param {String} str 富文本字符串
     * @returns {Array} 分割后的数组
     */
    splitRichText(str) {
      const parts = String(str).split(/###/g);
      const arr = [];

      for (let i = 0; i < parts.length; i++) {
        let content = parts[i] ?? '';

        // 偶数索引为普通文本段
        if (i % 2 === 0) {
          if (content === '') continue; // 跳过空文本块
          // 判断 content 最前面是否是标签
          const isStartWithTag = /^<[^>]+>/.test(content);

          if (!isStartWithTag) {
            content = this.setTag(i, parts, content);
          }

          arr.push({
            content,
            type: 'text',
            paragraph_list: [],
            paragraph_list_parameter: {
              text: '',
              pinyin_proofread_word_list: [],
            },
          });
          continue;
        }

        // 奇数索引为输入段（被 ### 包裹的分割符）
        const separatorContent = content;
        const isUnderline = /^_{3,}$/.test(separatorContent);
        const richFillMatch = separatorContent.match(/^<span[^>]*class="[^"]*rich-fill[^"]*"[^>]*>(.*?)<\/span>$/i);
        const answerValue = isUnderline ? '' : richFillMatch ? richFillMatch[1] : separatorContent;
        const mark = getRandomNumber();

        arr.push({
          content: separatorContent,
          type: 'input',
          input: '',
          audio_answer_list: [],
          mark,
          paragraph_list: [],
          paragraph_list_parameter: {
            text: '',
            pinyin_proofread_word_list: [],
          },
        });

        // 同步更新答案列表
        this.data.answer.answer_list.push({
          value: answerValue,
          mark,
          type: isUnderline ? 'any_one' : 'only_one',
        });
      }
      return arr;
    },

    /**
     * 设置前一个标签
     * @param {Number} index 当前索引
     * @param {Array} parts 分割后的数组
     * @param {String} content 当前内容
     * @returns {String} 包含向前两个标签内容中最后一个html标签的内容
     */
    setTag(index, parts, content) {
      if (index < 2) return content;
      let _content = content;
      const isEndWithTag = /<\/[^>]+>$/.test(_content); // 判断是否以标签结尾
      let startTag = '';
      const part = parts[index - 2] ?? '';
      const tagMatch = part.match(/<[^>]+>/g);
      if (tagMatch) {
        startTag = tagMatch[tagMatch.length - 1]; // 获取最后一个标签
      }
      _content = `${startTag}${_content}`;
      if (!isEndWithTag) {
        let tag = startTag.match(/^<([^>\s]+).*?>/);
        tag = tag ? tag[1] : 'span';
        _content += `</${tag}>`;
      }
      return _content;
    },
    handleTone(value, i) {
      if (!/^[a-zA-Z0-9\s]+$/.test(value)) return;
      this.data.answer.answer_list[i].value = value
        .trim()
        .split(/\s+/)
        .map((item) => {
          return handleToneValue(item);
        })
        .map((item) =>
          item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
        )
        .filter((item) => item.length > 0)
        .join(' ');
    },
    uploads(file_id) {
      this.data.audio_file_id = file_id;
    },
    deleteFiles() {
      this.data.audio_file_id = '';
    },
    // 自动生成音频
    handleMatic() {
      TextToAudioFile({
        text: this.data.content.replace(/<[^>]+>/g, ''),
        voice_type: this.data.property.voice_type,
        emotion: this.data.property.emotion,
        speed_ratio: this.data.property.speed_ratio,
      })
        .then(({ status, file_id }) => {
          if (status === 1) {
            this.data.audio_file_id = file_id;
          }
        })
        .catch(() => {});
    },
    /**
     * @description 处理思维导图数据
     */
    handleMindMap() {
      const { arrange_type } = this.data.property;
      const arrangeLabel = arrangeTypeList.find((item) => item.value === arrange_type)?.label || '';
      this.data.mind_map.node_list = [
        {
          name: `${arrangeLabel}填空组件`,
        },
      ];
    },
    handleViewPinyin() {
      if (!this.isEnable(this.data.property.view_pinyin)) {
        return;
      }

      this.data.model_essay.forEach((item, i) => {
        item.forEach((option, j) => {
          const text = option.content;
          option.paragraph_list_parameter.text = text;

          this.createParsedTextInfoPinyin(text, i, j, 'model_essay');
        });
      });
    },
    openAddWord() {
      this.visibleWord = true;
    },
    /**
     * 添加词汇
     * @param {string} word 词汇内容
     */
    addWord(word) {
      if (!word) return;
      this.data.word_list.push({
        content: word,
        mark: getRandomNumber(),
      });
    },
    removeWord(index) {
      this.data.word_list.splice(index, 1);
    },
  },
};
</script>

<style lang="scss" scoped>
.fill-wrapper {
  display: flex;
  flex-direction: column;
  row-gap: 16px;
  align-items: flex-start;

  :deep .rich-wrapper {
    width: 100%;
  }

  .select-vocabulary {
    .title {
      margin: 0 0 8px;
    }

    .word-list {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin-top: 8px;

      .word-item {
        display: flex;
        gap: 6px;
        align-items: center;
        padding: 4px 6px;
        border: $border;
        border-radius: 4px;

        :deep p {
          margin: 0;
        }

        .delete-word {
          display: flex;
          align-items: center;
          padding: 0;
          line-height: 1;
        }
      }
    }
  }

  .tips {
    font-size: 12px;
    color: #999;
  }

  .auto-matic,
  .upload-audio-play {
    :deep .upload-wrapper {
      margin-top: 0;
    }

    .audio-wrapper {
      :deep .audio-play {
        width: 16px;
        height: 16px;
        color: #000;
        background-color: initial;
      }

      :deep .audio-play.not-url {
        color: #a1a1a1;
      }

      :deep .voice-play {
        width: 16px;
        height: 16px;
      }
    }
  }

  .auto-matic {
    display: flex;
    flex-shrink: 0;
    column-gap: 12px;
    align-items: center;
    width: 200px;
    padding: 5px 12px;
    background-color: $fill-color;
    border-radius: 2px;

    .auto-btn {
      font-size: 16px;
      font-weight: 400;
      line-height: 22px;
      color: #1d2129;
      cursor: pointer;
    }
  }

  .correct-answer {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;

    .el-input {
      width: 180px;

      :deep &__prefix {
        display: flex;
        align-items: center;
        color: $text-color;
      }
    }
  }
}

.pinyin-text-list {
  :deep .pinyin-area {
    display: inline;
  }

  :deep .pinyin-area .rich-text-container,
  :deep .pinyin-area .pinyin-paragraph {
    display: inline;
  }
}
</style>
