<template>
  <div class="pinyin-area" :style="{ 'text-align': pinyinOverallPosition, padding: pinyinPadding }">
    <AudioPlay
      v-if="isEnable(isEnableVoice)"
      :file-id="audioFileId"
      :theme-color="unifiedAttrib && unifiedAttrib.topic_color ? unifiedAttrib.topic_color : ''"
    />

    <!-- 新规则：使用 richTextList -->
    <div v-if="richTextList && richTextList.length > 0" class="rich-text-container">
      <template v-for="(block, index) in parsedBlocks">
        <!-- 文字块：包含 word_list -->
        <span
          v-if="block.type === 'text'"
          :key="'text-' + index"
          class="pinyin-sentence"
          :style="[{ 'align-items': pinyinPosition === 'top' ? 'flex-end' : 'flex-start' }, block.styleObj]"
        >
          <span v-for="(word, wIndex) in block.word_list" :key="wIndex" class="pinyin-text">
            <span
              :class="{ active: visible && word_index == wIndex && sentence_index === block.index }"
              :title="isPreview ? '' : '点击校对'"
              :style="{
                cursor: isPreview ? '' : 'pointer',
              }"
              @click="correctPinyin(word, block.paragraphIndex, block.oldIndex, wIndex)"
            >
              <span v-for="(char, cIndex) in Array.from(word.text)" :key="cIndex">
                <span
                  :style="{
                    flexDirection: pinyinPosition === 'top' ? 'column' : 'column-reverse',
                    'align-items': getWordAlignItems(word, block),
                  }"
                >
                  <span class="pinyin" :style="getPinyinStyle(word)"> {{ getCharPinyin(word, cIndex) }}</span>
                  <span class="py-char" :style="getCharStyle(word, block, cIndex)">{{ convertText(char) }}</span>
                </span>
              </span>
            </span>
          </span>
        </span>
        <!-- 图片块 -->
        <div
          v-else-if="block.type === 'image'"
          :key="'image-' + index"
          :style="block.containerStyle"
          class="image-container"
        >
          <img
            :src="block.src"
            :alt="block.alt"
            :width="block.width"
            :height="block.height"
            :style="block.imageStyle"
            class="inline-image"
          />
        </div>
        <!-- 换行符 -->
        <br v-else-if="block.type === 'newline'" :key="'newline-' + index" />
      </template>
    </div>

    <!-- 老规则：使用 paragraphList -->
    <template v-else-if="paragraphList && paragraphList.length > 0">
      <div v-for="(paragraph, pIndex) in paragraphList" :key="pIndex" class="pinyin-paragraph">
        <div
          v-for="(sentence, sIndex) in paragraph"
          :key="sIndex"
          class="pinyin-sentence"
          :style="{ 'align-items': pinyinPosition === 'top' ? 'flex-end' : 'flex-start' }"
        >
          <span v-for="(word, wIndex) in sentence" :key="wIndex" class="pinyin-text">
            <span
              :class="{
                active: visible && word_index == wIndex && sentence_index === sIndex && paragraph_index === pIndex,
              }"
              :title="isPreview ? '' : '点击校对'"
              :style="{
                cursor: isPreview ? '' : 'pointer',
                'align-items': wIndex == 0 ? 'flex-start' : 'center',
              }"
              @click="correctPinyin(word, pIndex, sIndex, wIndex)"
            >
              <span
                v-if="pinyinPosition === 'top' && hasPinyinInParagraph(sIndex)"
                class="pinyin"
                :style="{ 'font-size': pinyinSize }"
              >
                {{ getPinyinText(word) }}</span
              >
              <span class="py-char" :style="textStyle(word)">{{ convertText(word.text) }}</span>
              <span
                v-if="pinyinPosition !== 'top' && hasPinyinInParagraph(sIndex)"
                class="pinyin"
                :style="{ 'font-size': pinyinSize }"
              >
                {{ getPinyinText(word) }}</span
              >
            </span>
          </span>
        </div>
      </div>
    </template>

    <CorrectPinyin
      :visible.sync="visible"
      :new-version="newVersion"
      :select-content="selectContent"
      :component-type="componentType"
      @fillTonePinyin="fillTonePinyin"
    />

    <el-dialog
      ref="optimizedDialog"
      title=""
      :visible.sync="noteDialogVisible"
      width="680px"
      :style="dialogStyle"
      :close-on-click-modal="false"
      destroy-on-close
      @close="noteDialogVisible = false"
    >
      <span v-html="sanitizeHTML(note)"></span>
    </el-dialog>
  </div>
</template>

<script>
import CorrectPinyin from '@/views/book/courseware/create/components/base/common/CorrectPinyin.vue';
import { sanitizeHTML } from '@/utils/common';
import { isEnable } from '@/views/book/courseware/data/common';
import AudioPlay from '@/views/book/courseware/preview/components/character_base/components/AudioPlay.vue';

export default {
  name: 'PinyinText',
  components: {
    CorrectPinyin,
    AudioPlay,
  },
  inject: ['convertText'],
  props: {
    isEnableVoice: {
      type: String,
      default: 'false',
    },
    audioFileId: {
      type: String,
      default: '',
    },
    unifiedAttrib: {
      type: Object,
      default: () => ({}),
    },
    paragraphList: {
      type: Array,
      default: () => [],
    },
    richTextList: {
      type: Array,
      default: () => [],
    },
    pinyinPosition: {
      type: String,
      required: true,
    },
    fontFamily: {
      type: String,
      default: '',
    },
    fontSize: {
      type: String,
      default: '12pt',
    },
    pinyinSize: {
      type: String,
      default: '12pt',
    },
    pinyinOverallPosition: {
      type: String,
      default: 'left',
    },
    isPreview: {
      type: Boolean,
      default: false,
    },
    componentType: {
      type: String,
      default: '',
    },
    pinyinPadding: {
      type: String,
      default: '0px 0px 0px 0px',
    },
  },
  data() {
    return {
      isEnable,
      sanitizeHTML,
      visible: false,
      selectContent: {},
      paragraph_index: 0,
      sentence_index: 0,
      word_index: 0,
      noteDialogVisible: false,
      note: '',
      dialogStyle: {
        position: 'fixed',
        top: '0',
        left: '0',
        margin: '0',
      },
      isAllSetting: false,
    };
  },
  computed: {
    newVersion() {
      return this.richTextList && this.richTextList.length > 0;
    },
    styleWatch() {
      return {
        fontSize: this.fontSize,
        fontFamily: this.fontFamily,
      };
    },
    // 解析 richTextList 为可渲染的块
    parsedBlocks() {
      if (!this.richTextList || this.richTextList.length === 0) return [];

      const blocks = [];
      let textBlockIndex = 0;
      let oldIndex = -1;
      let paragraphIndex = 0;
      const tagStack = [];

      for (const item of this.richTextList) {
        oldIndex += 1;

        if (item.text && typeof item.text === 'string' && item.text.includes('<img')) {
          blocks.push(this.parseImageBlock(item, tagStack));
        } else if (item.is_style === 'true' || item.is_style === true) {
          this.handleStyleTag(item, tagStack);
        } else if (item.text === '\n') {
          blocks.push({ type: 'newline' });
          paragraphIndex += 1;
        } else if (item.word_list && item.word_list.length > 0) {
          const hasEmphasisDot = this.checkHasEmphasisDot(tagStack);
          blocks.push(this.createTextBlock(item, tagStack, textBlockIndex, oldIndex, paragraphIndex, hasEmphasisDot));
          textBlockIndex += 1;
        }
      }

      return blocks;
    },
  },
  watch: {
    styleWatch: {
      handler() {
        this.isAllSetting = true;
      },
      immediate: true,
      deep: true,
    },
  },
  methods: {
    // 检查标签栈中是否有着重点样式
    checkHasEmphasisDot(tagStack) {
      return tagStack.some((tagItem) => {
        if (!tagItem.className) return false;
        return tagItem.className.includes('rich-text-emphasis-dot');
      });
    },

    // 解析图片块
    parseImageBlock(item, tagStack) {
      const imgMatch = item.text.match(/<img\s+([^>]*)\/?\s*>/i);
      if (!imgMatch) return null;

      const attrs = imgMatch[1];
      const srcMatch = attrs.match(/src=["']([^"']*)["']/i);
      const altMatch = attrs.match(/alt=["']([^"']*)["']/i);
      const widthMatch = attrs.match(/width=["']?(\d+)["']?/i);
      const heightMatch = attrs.match(/height=["']?(\d+)["']?/i);
      const styleMatch = attrs.match(/style=["']([^"']*)["']/i);

      const containerStyleObj = {};
      tagStack.forEach((tagItem) => {
        if (tagItem.style) {
          this.mergeStyleString(containerStyleObj, tagItem.style);
        }
      });

      const imageStyleObj = {};
      if (styleMatch) {
        this.mergeStyleString(imageStyleObj, styleMatch[1]);
      }

      return {
        type: 'image',
        src: srcMatch ? srcMatch[1] : '',
        alt: altMatch ? altMatch[1] : '',
        width: widthMatch ? widthMatch[1] : null,
        height: heightMatch ? heightMatch[1] : null,
        containerStyle: containerStyleObj,
        imageStyle: imageStyleObj,
      };
    },

    // 合并样式字符串到对象
    mergeStyleString(styleObj, styleStr) {
      styleStr.split(';').forEach((rule) => {
        if (rule.trim()) {
          const [prop, value] = rule.split(':').map((s) => s.trim());
          if (prop && value) {
            const camelProp = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
            styleObj[camelProp] = value;
          }
        }
      });
    },

    // 处理样式标签
    handleStyleTag(item, tagStack) {
      const tagText = item.text || '';
      const closeTagMatch = tagText.match(/^<\/(\w+)>$/);

      if (closeTagMatch) {
        const tagName = closeTagMatch[1];
        this.removeTagFromStack(tagStack, tagName);
      } else {
        const openTagMatch = tagText.match(/^<(\w+)([^>]*)>$/);
        if (openTagMatch) {
          const tagName = openTagMatch[1];
          const attrs = openTagMatch[2];
          const { style, className } = this.extractTagInfo(attrs, tagName);
          tagStack.push({ tag: tagName, style, className });
        }
      }
    },

    // 提取标签信息（样式和类名）
    extractTagInfo(attrs, tagName) {
      const styleMatch = attrs.match(/style=["']([^"']*)["']/);
      let style = styleMatch ? styleMatch[1] : null;

      const classMatch = attrs.match(/class=["']([^"']*)["']/);
      const className = classMatch ? classMatch[1] : '';

      if (!style) {
        style = this.getDefaultTagStyle(tagName);
      }

      return { style, className };
    },

    // 获取标签默认样式
    getDefaultTagStyle(tagName) {
      const tagStyleMap = {
        strong: 'font-weight: bold',
        b: 'font-weight: bold',
        em: 'font-style: italic',
        i: 'font-style: italic',
        u: 'text-decoration: underline',
        s: 'text-decoration: line-through',
        del: 'text-decoration: line-through',
        sub: 'vertical-align: sub',
        sup: 'vertical-align: super',
      };
      return tagStyleMap[tagName] || null;
    },

    // 创建文本块
    createTextBlock(item, tagStack, textBlockIndex, oldIndex, paragraphIndex, hasEmphasisDot) {
      const combinedStyle = tagStack
        .filter((tagItem) => tagItem.style)
        .map((tagItem) => tagItem.style)
        .join(';');

      const styleObj = combinedStyle ? this.parseStyleToObject(combinedStyle) : null;

      return {
        type: 'text',
        word_list: item.word_list,
        index: textBlockIndex,
        oldIndex,
        paragraphIndex,
        styleObj,
        hasEmphasisDot,
      };
    },

    // 解析样式字符串为对象
    parseStyleToObject(styleStr) {
      const styleObj = {};
      if (!styleStr) return styleObj;

      this.mergeStyleString(styleObj, styleStr);
      return styleObj;
    },

    // 获取单个字符的样式（包括着重点）
    getCharStyle(word, block, charIndex) {
      const baseStyle = { ...word.activeTextStyle };
      baseStyle['font-size'] = baseStyle.fontSize;
      baseStyle['font-family'] = baseStyle.fontFamily;

      if (this.isAllSetting) {
        baseStyle['font-size'] = this.fontSize;
        baseStyle['font-family'] = this.fontFamily;
        this.isAllSetting = false;
      }

      // 如果该文字块有着重点标记，应用到字符上
      if (block.hasEmphasisDot) {
        const letterSpacing = block.styleObj?.letterSpacing || '0';
        const letterSpacingValue = parseFloat(letterSpacing) || 0;

        baseStyle['border-bottom'] = 'none';
        baseStyle['background-image'] = 'radial-gradient(circle at center, currentColor 0.15em, transparent 0.16em)';
        baseStyle['background-repeat'] = 'repeat-x';
        baseStyle['background-position'] = `${letterSpacingValue * -0.5}em 100%`;
        baseStyle['background-size'] = `${1 + letterSpacingValue}em 0.3em`;
        baseStyle['padding-bottom'] = '0.3em';
        baseStyle['display'] = 'inline';
      }

      return baseStyle;
    },
    // 兼容历史数据
    getPinyinText(item) {
      return this.checkShowPinyin(item.showPinyin) ? item.pinyin.replace(/\s+/g, '') : '\u200B';
    },
    // 拼音与汉字一一对应
    getCharPinyin(word, charIndex) {
      if (!this.checkShowPinyin(word.showPinyin)) {
        return '\u200B';
      }
      // 优先使用新的 pinyin_list 字段（与字符一一对应）
      if (word.pinyin_list && Array.isArray(word.pinyin_list)) {
        return word.pinyin_list[charIndex] || '\u200B';
      }
      // 兼容旧数据：使用 pinyin 字段
      const pinyinList = word.pinyin ? word.pinyin.trim().split(/\s+/) : [];
      return pinyinList[charIndex] || '\u200B';
    },
    // 如果汉字有字间距，拼音与汉字左对齐，如果没有则居中对齐
    getWordAlignItems(word, block) {
      const letterSpacing = block.styleObj?.letterSpacing;
      if (letterSpacing && letterSpacing !== '0' && letterSpacing !== '0px') {
        return 'flex-start';
      }
      return 'center';
    },
    // 拼音固定为拼音字体，跟随汉字的字号、颜色、粗细的样式
    getPinyinStyle(item) {
      const styles = {};

      // 固定使用 League 字体
      styles['font-family'] = 'League';

      // 只继承字号和颜色
      if (item.activeTextStyle) {
        if (item.activeTextStyle.fontSize) {
          styles['font-size'] = item.activeTextStyle.fontSize;
        }
        if (item.activeTextStyle.color) {
          styles['color'] = item.activeTextStyle.color;
        }
      }

      // 如果设置了全局字号，优先使用全局字号
      if (this.isAllSetting && this.fontSize) {
        styles['font-size'] = this.fontSize;
        this.isAllSetting = false;
      }

      // 明确重置不应该继承的样式
      styles['text-decoration'] = 'none';
      styles['font-style'] = 'normal';
      styles['letter-spacing'] = '0';

      return styles;
    },
    removeTagFromStack(tagStack, tagName) {
      for (let i = tagStack.length - 1; i >= 0; i--) {
        if (tagStack[i].tag === tagName) {
          tagStack.splice(i, 1);
          break;
        }
      }
    },
    textStyle(item) {
      const styles = { ...item.activeTextStyle };
      styles['font-size'] = styles.fontSize;
      styles['font-family'] = styles.fontFamily;

      if (this.isAllSetting) styles['font-size'] = this.fontSize;
      if (this.isAllSetting) styles['font-family'] = this.fontFamily;
      this.isAllSetting = false;
      return styles;
    },
    /**
     * 校对拼音
     */
    correctPinyin(item, pIndex, sIndex, wIndex) {
      if (this.isPreview) {
        if (item.note) {
          this.note = item.note;

          this.noteDialogVisible = true;
          this.$nextTick(() => {
            const dialogElement = this.$refs.optimizedDialog;
            // 确保对话框 DOM 已渲染
            if (!dialogElement) {
              return;
            }
            // 获取对话框内容区域的 DOM 元素
            const dialogContent = dialogElement.$el.querySelector('.el-dialog');
            if (!dialogContent) {
              return;
            }
            const dialogRect = dialogContent.getBoundingClientRect();
            const dialogWidth = dialogRect.width;
            const dialogHeight = dialogRect.height;
            const padding = 10; // 安全边距

            const clickX = event.clientX;
            const clickY = event.clientY;

            const windowWidth = window.innerWidth;
            const windowHeight = window.innerHeight;

            // 水平定位 - 中心对齐
            let left = clickX - dialogWidth / 2;
            // 边界检查
            left = Math.max(padding, Math.min(left, windowWidth - dialogWidth - padding));

            // 垂直定位 - 点击位置作为下边界中心
            let top = clickY - dialogHeight;
            // 上方空间不足时，改为向下展开
            if (top < padding) {
              top = clickY + padding;
              // 如果向下展开会超出屏幕，则贴底部显示
              if (top + dialogHeight > windowHeight - padding) {
                top = windowHeight - dialogHeight - padding;
              }
            }

            this.dialogStyle = {
              position: 'fixed',
              top: `${top - 20}px`,
              left: `${left}px`,
              margin: '0',
              transform: 'none',
            };
          });
        }
        return;
      } // 如果是预览模式，不操作
      if (item) {
        this.visible = true;
        this.selectContent = item;
        this.paragraph_index = pIndex;
        this.sentence_index = sIndex;
        this.word_index = wIndex;
      }
    },
    // 回填校对后的拼音
    fillTonePinyin(dataContent) {
      this.$emit('fillCorrectPinyin', {
        selectContent: dataContent,
        i: this.paragraph_index,
        j: this.sentence_index,
        k: this.word_index,
        newVersion: this.newVersion,
      });
    },
    // 如段落有拼音，则返回true ，否则不显示拼音行
    hasPinyinInParagraph(paragraphIndex) {
      const paragraph = this.paragraphList[paragraphIndex];
      return paragraph.some((sentence) => sentence.some((item) => this.checkShowPinyin(item.showPinyin)));
    },
    hasPinyinInParagraphNeVersion(paragraphIndex) {
      const paragraphs = this.parsedBlocks.filter((item) => item.paragraphIndex === paragraphIndex);

      return paragraphs.flatMap((item) => item.word_list).some((item) => this.checkShowPinyin(item.showPinyin));
    },
    // 兼容历史数据，没有 showPinyin 字段的，则默认为 true
    checkShowPinyin(showPinyin) {
      if (showPinyin === undefined || showPinyin === null) {
        return true;
      }
      return this.isEnable(showPinyin);
    },
  },
};
</script>

<style lang="scss" scoped>
.pinyin-area {
  // 新规则的容器样式
  .rich-text-container {
    p {
      display: inline-flex;
      flex-wrap: wrap;
      margin: 0.5em 0;
    }

    span {
      display: inline-flex;
    }

    .pinyin-sentence {
      display: inline-flex;
      flex-wrap: wrap;
    }

    .image-container {
      display: block;

      .inline-image {
        display: inline-block;
        max-width: 100%;
        height: auto;
      }
    }
  }

  .pinyin-paragraph {
    .pinyin-sentence {
      display: inline-flex;
      flex-wrap: wrap;
    }
  }

  .pinyin-text {
    padding: 0 2px;

    // font-size: 16px;
    text-wrap: pretty;
    hanging-punctuation: allow-end;

    > span {
      display: inline-flex;

      // flex-direction: column;
    }

    .py-char {
      ruby-align: center;
      line-height: 1em;
    }

    .pinyin {
      display: inline-block;
      min-height: 12px;
      font-family: 'League';

      // font-family: 'PINYIN-B';
      // font-size: 12px;
      // font-weight: lighter;
      // line-height: 12px;
      // color: $font-color;
      line-height: 1em;
      text-decoration: none !important;

      // 防止继承父元素的删除线
      text-decoration-skip-ink: none;
    }
  }

  .active {
    color: rgb(242, 85, 90) !important;
  }
}
</style>

<style lang="scss">
.pinyin-area + .pinyin-area {
  margin-top: 4px;
}
</style>
