<!-- eslint-disable vue/no-v-html -->
<template>
  <div class="fill-preview">
    <div class="stem">
      <span class="question-number" :style="{ fontSize: data.property.stem_question_number }">
        {{ data.property.question_number }}.
      </span>
      <span v-html="sanitizeHTML(data.stem)"></span>
    </div>
    <div v-if="isEnable(data.property.is_enable_description)" class="description">
      <span v-for="(text, i) in descriptionList" :key="i" class="description-item" @click="selectedDescription(text)">
        {{ text }}
      </span>
    </div>

    <div class="fill-wrapper">
      <p v-for="(item, i) in modelEssay" :key="i">
        <template v-for="(li, j) in item">
          <span v-if="li.type === 'text'" :key="j" v-html="sanitizeHTML(li.content)"></span>
          <template v-if="li.type === 'input'">
            <el-input
              :key="j"
              v-model="li.content"
              :disabled="disabled"
              :class="[...computedAnswerClass(li.mark)]"
              :style="[{ width: Math.max(80, li.content.length * 21.3) + 'px' }]"
              @focus="handleInputFocus(i, j)"
              @blur="handleTone(li.content, i, j)"
            />
            <span v-show="computedAnswerText(li.mark).length > 0" :key="`answer-${j}`" class="right-answer">
              {{ computedAnswerText(li.mark) }}
            </span>
          </template>
        </template>
      </p>
    </div>
  </div>
</template>

<script>
import PreviewMixin from './components/PreviewMixin';

import { addTone } from '@/views/exercise_questions/data/common';
import { handleToneValue } from '@/views/exercise_questions/data/fill';

export default {
  name: 'FillPreview',
  mixins: [PreviewMixin],
  data() {
    return {
      modelEssay: [],
      inputFocus: false,
      focusPostion: {
        i: -1,
        j: -1,
      },
    };
  },
  computed: {
    descriptionList() {
      return this.data.description.split(/\s+/).filter((item) => item);
    },
  },
  watch: {
    'data.model_essay': {
      handler(val) {
        if (!val) return;
        this.modelEssay = JSON.parse(JSON.stringify(val));
      },
      deep: true,
      immediate: true,
    },
    modelEssay: {
      handler(val) {
        if (!val) return;
        this.answer.answer_list = val
          .map((item) => {
            return item
              .map(({ type, content, mark }) => {
                if (type === 'input') {
                  return {
                    value: content,
                    mark,
                  };
                }
              })
              .filter((item) => item);
          })
          .flat();
      },
      deep: true,
      immediate: true,
    },
    isJudgingRightWrong(val) {
      if (!val) return;
      this.answer.answer_list.forEach(({ mark, value }) => {
        this.modelEssay.forEach((item) => {
          item.forEach((li) => {
            if (li.mark === mark) {
              li.content = value;
            }
          });
        });
      });
    },
  },
  created() {
    document.addEventListener('click', this.handleBlur);
    document.addEventListener('keydown', this.handleBlurTab);
  },
  beforeDestroy() {
    document.removeEventListener('click', this.handleBlur);
    document.removeEventListener('keydown', this.handleBlurTab);
  },
  methods: {
    /**
     * 处理点击失焦
     * @param {MouseEvent} e
     */
    handleBlur(e) {
      if (e.target.tagName === 'INPUT') return;
      this.inputFocus = false;
    },
    /**
     * 处理 tab 键失焦
     * @param {KeyboardEvent} e
     */
    handleBlurTab(e) {
      if (e.key !== 'Tab') return;
      this.inputFocus = false;
    },
    /**
     * 处理输入框聚焦
     * @param {number} i
     * @param {number} j
     */
    handleInputFocus(i, j) {
      this.inputFocus = true;
      this.focusPostion = {
        i,
        j,
      };
    },
    /**
     * 选中描述
     * @param {string} text 描述文本
     */
    selectedDescription(text) {
      if (!this.inputFocus) return;
      const { i, j } = this.focusPostion;
      this.modelEssay[i][j].content = text;
      this.inputFocus = false;
    },
    handleTone(value, i, j) {
      if (!/^[a-zA-Z0-9\s]+$/.test(value)) return;
      this.modelEssay[i][j].content = 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(' ');
    },
    /**
     * 计算答题对错选项字体颜色
     * @param {string} mark 选项标识
     */
    computedAnswerClass(mark) {
      if (!this.isJudgingRightWrong && !this.isShowRightAnswer) {
        return '';
      }
      let selectOption = this.answer.answer_list.find((item) => item.mark === mark);
      let answerOption = this.data.answer.answer_list.find((item) => item.mark === mark);
      if (!selectOption) return '';
      let selectValue = selectOption.value;
      let answerValue = answerOption.value;
      let type = answerOption.type;
      let classList = [];
      let isRight =
        (type === 'only_one' && selectValue === answerValue) ||
        (type === 'any_one' && answerValue.split('/').includes(selectValue));

      if (this.isJudgingRightWrong) {
        isRight ? classList.push('right') : classList.push('wrong');
      }

      if (this.isShowRightAnswer && !isRight) {
        classList.push('show-right-answer');
      }
      return classList;
    },
    /**
     * 计算正确答案文本
     * @param {string} mark 选项标识
     */
    computedAnswerText(mark) {
      if (!this.isShowRightAnswer) return '';
      let selectOption = this.answer.answer_list.find((item) => item.mark === mark);
      let answerOption = this.data.answer.answer_list.find((item) => item.mark === mark);
      if (!selectOption) return '';
      let selectValue = selectOption.value;
      let answerValue = answerOption.value;
      let type = answerOption.type;
      let isRight =
        (type === 'only_one' && selectValue === answerValue) ||
        (type === 'any_one' && answerValue.split('/').includes(selectValue));
      if (isRight) return '';
      return `（${answerValue}）`;
    },
  },
};
</script>

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

.fill-preview {
  @include preview;

  .description {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 8px;

    &-item {
      padding: 4px 8px;
      cursor: pointer;
      background-color: #e9edf7;
      border-radius: 4px;

      &:hover,
      &:active {
        color: $light-main-color;
      }
    }
  }

  .fill-wrapper {
    font-size: 16pt;

    .el-input {
      display: inline-flex;
      align-items: center;
      width: 120px;
      margin: 0 2px;

      &.right {
        :deep input.el-input__inner {
          color: $right-color;
        }
      }

      &.wrong {
        :deep input.el-input__inner {
          color: $error-color;
        }
      }

      & + .right-answer {
        position: relative;
        left: -4px;
        display: inline-block;
        height: 32px;
        line-height: 28px;
        vertical-align: bottom;
        border-bottom: 1px solid $font-color;
      }

      :deep input.el-input__inner {
        padding: 0;
        font-size: 16pt;
        color: $font-color;
        text-align: center;
        background-color: #fff;
        border-width: 0;
        border-bottom: 1px solid $font-color;
        border-radius: 0;
      }
    }
  }
}
</style>
