<!-- eslint-disable vue/no-v-html -->
<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" :style="bodyStyles">
      <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.sentenceStyle]"
        >
          <span
            v-for="(word, wIndex) in block.word_list"
            :key="wIndex"
            :class="['pinyin-text', { spacing: isShowPinyin }]"
            :style="block.styleObj"
          >
            <span
              :title="isPreview ? '' : '点击校对'"
              :style="{
                cursor: isPreview ? '' : 'pointer',
              }"
              @click="!isPreview && handleWordClick(word, block.paragraphIndex, block.oldIndex, wIndex)"
              @mouseover="isPreview && handlePreviewHover(word, $event)"
              @mouseleave="onLeave"
            >
              <span
                v-if="word.pinyin_list && word.pinyin_list.length < Array.from(word.text).length"
                :style="{
                  flexDirection: pinyinPosition === 'top' ? 'column' : 'column-reverse',
                  'align-items': getWordAlignItems(word, block),
                }"
              >
                <span v-if="shouldShowWordPinyin(word)" class="pinyin" :style="getPinyinStyle(word, block)">
                  {{ getPinyinText(word) }}
                </span>
                <span class="py-char" :style="getCharStyle(word, block)">{{ convertText(word.text) }}</span>
              </span>
              <template v-else>
                <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 v-if="shouldShowWordPinyin(word)" class="pinyin" :style="getPinyinStyle(word, block)">
                      {{ getCharPinyin(word, cIndex) }}
                    </span>
                    <span class="py-char" :style="getCharStyle(word, block, cIndex)">{{ convertText(char) }}</span>
                  </span>
                </span>
              </template>
            </span>
          </span>
        </span>
        <!-- 图片块 -->
        <span
          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"
          />
        </span>

        <!-- 视频块 -->
        <span
          v-else-if="block.type === 'video'"
          :key="'video-' + index"
          :style="block.containerStyle"
          class="video-container"
        >
          <video
            :poster="block.poster"
            :width="block.width"
            :height="block.height"
            :style="block.mediaStyle"
            controls
            class="inline-video"
          >
            <source :src="block.src" :type="block.videoType" />
            您的浏览器不支持视频播放
          </video>
        </span>

        <!-- 音频块 -->
        <span
          v-else-if="block.type === 'audio'"
          :key="'audio-' + index"
          :style="block.containerStyle"
          class="audio-container"
        >
          <audio :src="block.src" :style="block.mediaStyle" controls class="inline-audio">
            您的浏览器不支持音频播放
          </audio>
        </span>

        <!-- 数学公式块（保留 MathJax 原始结构） -->
        <MathHtml
          v-else-if="block.type === 'math'"
          :key="'math-' + index"
          :html="block.html"
          :style-obj="block.containerStyle"
          :is-display="block.isDisplay"
        />
        <!-- 换行符 -->
        <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" :style="bodyStyles">
        <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', { spacing: isShowPinyin }]">
            <span
              :title="isPreview ? '' : '点击校对'"
              :style="{
                cursor: isPreview ? '' : 'pointer',
                'align-items': wIndex == 0 ? 'flex-start' : 'center',
              }"
              @click="!isPreview && handleWordClick(word, block.paragraphIndex, block.oldIndex, wIndex)"
              @mouseover="isPreview && handlePreviewHover(word, $event)"
              @mouseleave="onLeave"
            >
              <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-popover
      ref="notePopover"
      :popper-options="{ boundariesElement: 'viewport' }"
      placement="bottom-start"
      trigger="manual"
    >
      <div class="popover-content" style="max-width: 530px; font-size: 14pt" v-html="sanitizeHTML(note)"></div>
    </el-popover>
  </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';

// MathHtml 组件用于渲染数学公式的 HTML 内容，保留 MathJax 的原始结构
const MathHtml = {
  name: 'MathHtml',
  functional: true,
  props: {
    html: {
      type: String,
      default: '',
    },
    styleObj: {
      type: Object,
      default: () => ({}),
    },
    isDisplay: {
      type: Boolean,
      default: false,
    },
  },
  render(h, context) {
    return h('span', {
      class: {
        'math-container': true,
        'math-display': context.props.isDisplay,
      },
      style: context.props.styleObj,
      domProps: {
        innerHTML: sanitizeHTML(context.props.html || ''),
      },
    });
  },
};

export default {
  name: 'PinyinText',
  components: {
    CorrectPinyin,
    AudioPlay,
    MathHtml,
  },
  inject: ['convertText'],
  props: {
    isEnableVoice: {
      type: String,
      default: 'false',
    },
    audioFileId: {
      type: String,
      default: '',
    },
    unifiedAttrib: {
      type: Object,
      default: () => ({}),
    },
    paragraphList: {
      type: Array,
      default: () => [],
    },
    richTextList: {
      type: Array,
      default: () => [],
    },
    richTextNoteList: {
      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',
    },
    bodyStyles: {
      type: Object,
      default: () => ({}),
    },
    isShowPinyin: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      isEnable,
      sanitizeHTML,
      visible: false,
      selectContent: {},
      paragraph_index: 0,
      sentence_index: 0,
      word_index: 0,
      note: '',
      isAllSetting: false,
    };
  },
  computed: {
    newVersion() {
      return this.richTextList && this.richTextList.length > 0;
    },
    styleWatch() {
      return {
        fontSize: this.fontSize,
        fontFamily: this.fontFamily,
      };
    },

    // 预处理 richTextList，合并分散的视频标签
    normalizedRichTextList() {
      if (!this.richTextList || this.richTextList.length === 0) return [];

      const result = [];
      let i = 0;
      while (i < this.richTextList.length) {
        const item = this.richTextList[i];

        // 检查是否是视频开始标签（且不包含结束标签）
        if (
          item.text &&
          typeof item.text === 'string' &&
          item.text.includes('<video') &&
          !item.text.includes('</video>')
        ) {
          let combinedText = item.text;
          let j = i + 1;

          // 向后查找 source 和结束标签，直到遇到 </video> 或超出范围
          while (j < this.richTextList.length) {
            const nextItem = this.richTextList[j];
            if (nextItem.text) {
              combinedText += `${nextItem.text}`;
            }

            // 如果找到了结束标签，合并完成，跳出内部循环
            if (nextItem.text && nextItem.text.includes('</video>')) {
              j += 1; // 跳过结束标签
              break;
            }
            j += 1;
          }

          // 将合并后的内容作为一个新项加入结果
          result.push({
            ...item,
            text: combinedText,
            is_merged_video: true, // 标记一下，可选
          });

          // 更新主循环索引，跳过已合并的项
          i = j;
        } else {
          // 其他项直接加入
          result.push(item);
          i += 1;
        }
      }

      return result;
    },
    // 解析 richTextList 为可渲染的块
    parsedBlocks() {
      const listToParse = this.normalizedRichTextList;

      if (!listToParse || listToParse.length === 0) return [];
      const blocks = [];
      let textBlockIndex = 0;
      let oldIndex = -1;
      let paragraphIndex = 0;
      const tagStack = [];
      let mathContext = null;

      for (const item of listToParse) {
        oldIndex += 1;

        if (mathContext) {
          mathContext.html += this.getRawItemText(item);

          if (item.is_style === 'true' || item.is_style === true) {
            this.updateHtmlTagStack(mathContext.stack, item.text || '');
            if (mathContext.stack.length === 0) {
              blocks.push(this.parseMathBlock(mathContext.html, tagStack));
              mathContext = null;
            }
          }
          continue;
        }

        if (this.isMathRootTag(item)) {
          const rootTag = this.extractTagName(item.text || '');
          mathContext = {
            html: this.getRawItemText(item),
            stack: rootTag ? [rootTag] : ['span'],
          };
          continue;
        }

        if (item.text && typeof item.text === 'string' && item.text.includes('<img')) {
          blocks.push(this.parseImageBlock(item, tagStack));
        } else if (item.text && typeof item.text === 'string' && item.text.includes('<video')) {
          // item.text 是完整的 video 标签串
          blocks.push(this.parseVideoBlock(item, tagStack));
        } else if (item.text && typeof item.text === 'string' && item.text.includes('<audio')) {
          blocks.push(this.parseAudioBlock(item, tagStack));
        } else if (item.is_style === 'true' || item.is_style === true) {
          if (item.text.includes('<br')) {
            blocks.push({ type: 'newline' });
            paragraphIndex += 1;
          } else {
            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;
        }
      }

      if (mathContext) {
        blocks.push(this.parseMathBlock(mathContext.html, tagStack));
      }

      return blocks;
    },
  },
  watch: {
    styleWatch: {
      handler() {
        this.isAllSetting = true;
      },
      immediate: true,
      deep: true,
    },
  },
  methods: {
    // 统一处理点击事件
    handleWordClick(item, pIndex, sIndex, wIndex) {
      if (item) {
        this.visible = true;
        this.selectContent = item;
        this.paragraph_index = pIndex;
        this.sentence_index = sIndex;
        this.word_index = wIndex;
      }
    },
    // 预览模式：悬停触发气泡
    handlePreviewHover(item, event) {
      if (!item) return;
      let noteContent = '';
      // 查找注释内容
      if (item.annota_id && this.richTextNoteList) {
        const noteItem = this.richTextNoteList.find((p) => p.id === item.annota_id);
        if (noteItem) {
          noteContent = noteItem.dataStr || noteItem.note || '';
        }
      } else if (item.note) {
        noteContent = item.note;
      }
      if (noteContent) {
        this.note = noteContent;
        const refEl = this.$refs.notePopover;
        refEl.referenceElm = event.target;
        refEl.showPopper = true;
        // 强制重新计算定位
        if (refEl.updatePopper) {
          refEl.updatePopper();
        }
      }
    },
    onLeave() {
      this.$refs.notePopover.showPopper = false;
    },

    // 检查标签栈中是否有着重点样式
    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,
      };
    },

    // 解析视频块
    parseVideoBlock(item, tagStack) {
      const videoMatch = item.text.match(/<video\s+([^>]*)>/i);
      if (!videoMatch) return null;

      const attrs = videoMatch[1];
      const posterMatch = attrs.match(/poster=["']([^"']*)["']/i);
      const widthMatch = attrs.match(/width=["']?(\d+)["']?/i);
      const heightMatch = attrs.match(/height=["']?(\d+)["']?/i);
      const styleMatch = attrs.match(/style=["']([^"']*)["']/i);

      // 直接从完整的文本中匹配 source
      const sourceMatch = item.text.match(/<source\s+([^>]*)\/?\s*>/i);
      let src = '';
      let videoType = '';

      if (sourceMatch) {
        const sourceAttrs = sourceMatch[1];
        const srcMatch = sourceAttrs.match(/src\s*=\s*["']?([^"'\s>]+)["']?/i);
        const typeMatch = sourceAttrs.match(/type\s*=\s*["']?([^"'\s>]+)["']?/i);

        src = srcMatch ? srcMatch[1] : '';
        videoType = typeMatch ? typeMatch[1] : '';
      }

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

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

      return {
        type: 'video',
        poster: posterMatch ? posterMatch[1] : '',
        width: widthMatch ? widthMatch[1] : null,
        height: heightMatch ? heightMatch[1] : null,
        src,
        videoType,
        containerStyle: containerStyleObj,
        mediaStyle: mediaStyleObj,
      };
    },

    // 解析音频块
    parseAudioBlock(item, tagStack) {
      const audioMatch = item.text.match(/<audio\s+([^>]*)>/i);
      if (!audioMatch) return null;

      const attrs = audioMatch[1];
      const srcMatch = attrs.match(/src=["']([^"']*)["']/i);
      const styleMatch = attrs.match(/style=["']([^"']*)["']/i);

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

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

      return {
        type: 'audio',
        src: srcMatch ? srcMatch[1] : '',
        containerStyle: containerStyleObj,
        mediaStyle: mediaStyleObj,
      };
    },

    // 合并样式字符串到对象
    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;

      // 提取 paddingLeft 用于段落缩进，从 styleObj 中移除
      const sentenceStyle = {};
      if (styleObj && styleObj.paddingLeft) {
        sentenceStyle.paddingLeft = styleObj.paddingLeft;
        delete styleObj.paddingLeft;
      }

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

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

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

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

      const isDisplay =
        /<mjx-container[^>]*\bdisplay=["']true["']/i.test(html) ||
        /<mjx-assistive-mml[^>]*\bdisplay=["']block["']/i.test(html);

      return {
        type: 'math',
        html,
        containerStyle: containerStyleObj,
        isDisplay,
      };
    },

    isMathRootTag(item) {
      if (!item || !(item.is_style === 'true' || item.is_style === true) || !item.text) return false;
      return /class=["'][^"']*\bmathjax-container\b[^"']*\beditor-math\b[^"']*["']/i.test(item.text);
    },

    getRawItemText(item) {
      if (!item) return '';
      return item.text || '';
    },

    extractTagName(tagText) {
      const match = (tagText || '').match(/^<\/?\s*([a-zA-Z][\w-]*)/);
      return match ? match[1].toLowerCase() : '';
    },

    updateHtmlTagStack(tagStack, tagText) {
      if (!tagText || !tagStack) return;

      const tagName = this.extractTagName(tagText);
      if (!tagName) return;

      if (/^<\//.test(tagText)) {
        for (let i = tagStack.length - 1; i >= 0; i--) {
          if (tagStack[i] === tagName) {
            tagStack.splice(i, 1);
            break;
          }
        }
      } else if (!/\/>\s*$/.test(tagText)) {
        tagStack.push(tagName);
      }
    },

    getBlockColor(block) {
      const colorFromObject = block?.styleObj?.color;
      if (colorFromObject) return colorFromObject;

      const styleText = block?.rawStyleText || '';
      const colorMatch = styleText.match(/(?:^|;)\s*color\s*:\s*([^;]+)/i);
      return colorMatch ? colorMatch[1].trim() : '';
    },

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

      const blockColor = this.getBlockColor(block);
      if (blockColor) {
        baseStyle.color = `${blockColor} !important`;
      }

      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.08em, transparent 0.09em)';
        baseStyle['background-repeat'] = 'repeat-x';
        baseStyle['background-position'] = `${letterSpacingValue * -0.5}em 100%`;
        baseStyle['background-size'] = `${1 + letterSpacingValue}em 0.15em`;
        baseStyle['padding-bottom'] = '0.15em';
        baseStyle['display'] = 'inline';
      }

      return baseStyle;
    },
    // 兼容历史数据
    getPinyinText(item) {
      return this.checkShowPinyin(item.showPinyin) ? item.pinyin.replace(/\s+/g, '') : '\u200B';
    },
    shouldShowWordPinyin(item) {
      return this.checkShowPinyin(item && item.showPinyin);
    },
    // 拼音与汉字一一对应
    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, block) {
      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;
        }
      }

      const blockColor = this.getBlockColor(block);
      if (blockColor) {
        styles['color'] = `${blockColor} !important`;
      }

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

      // 优先取文字单独的字号
      let _fontSize = block.styleObj && block.styleObj.fontSize ? block.styleObj.fontSize : null;
      // 如果没有，取继承的字号
      if (!_fontSize && item.activeTextStyle && item.activeTextStyle.fontSize) {
        _fontSize = item.activeTextStyle.fontSize;
      }
      // 如果没有，取组件的字号
      if (!_fontSize && this.bodyStyles.fontSize) _fontSize = this.bodyStyles.fontSize;
      // 如果没有，取全局字号
      if (!_fontSize && this.fontSize) _fontSize = this.fontSize;

      if (_fontSize) {
        // 取出字号里面的数字，做计算处理之后，自动加上原来的单位
        const fontSizeMatch = _fontSize.match(/^([\d.]+)(\D*)$/);
        if (fontSizeMatch) {
          const fontSizeValue = parseFloat(fontSizeMatch[1]);
          const fontSizeUnit = fontSizeMatch[2] || 'px';

          // 根据字号大小确定比例:16号及以下75%,16号以上60%
          const ratio = fontSizeValue <= 16 ? 0.75 : 0.6;
          const calculatedSize = Math.round(fontSizeValue * ratio);

          // 保留原始单位
          styles['font-size'] = `${calculatedSize}${fontSizeUnit}`;
        }
      }
      // 明确重置不应该继承的样式
      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;
    },
    // 回填校对后的拼音
    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) {
      if (!this.isShowPinyin) {
        return false;
      }
      const paragraph = this.paragraphList[paragraphIndex];
      return paragraph.some((sentence) => sentence.some((item) => this.checkShowPinyin(item.showPinyin)));
    },
    // 兼容历史数据，没有 showPinyin 字段的，则默认为 true
    checkShowPinyin(showPinyin) {
      if (!this.isShowPinyin) {
        return false;
      }
      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;
    }

    :deep(.mathjax-container.editor-math > svg[aria-hidden='true']) {
      display: none !important;
    }

    .math-container.math-display {
      display: block !important;
      width: 100%;
      text-align: center;
    }

    .math-container.math-display :deep(mjx-container[display='true']) {
      display: block !important;
      margin: 0 auto;
      text-align: center;
    }

    span {
      display: inline-flex;
    }

    .pinyin-sentence {
      display: inline;
      white-space: normal;
    }

    .image-container {
      display: inline-block;

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

    .video-container {
      display: inline-block;
      margin: 26px 5px 26px 0;

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

    .audio-container {
      display: block;

      .inline-audio {
        display: inline-block;
        width: 100%;
        max-width: 500px;
      }
    }
  }

  .pinyin-paragraph {
    .pinyin-sentence {
      display: inline;
      white-space: normal;
    }
  }

  .pinyin-text {
    display: inline-flex;
    text-wrap: pretty;
    hanging-punctuation: allow-end;

    &.spacing {
      padding: 0 2px;
    }

    > span {
      display: inline-flex;
    }

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

    .pinyin {
      display: inline-block;
      min-height: 12px;
      font-family: 'League';
      line-height: 1em;
      text-decoration: none !important;

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

  :deep(.annotation-popover) {
    z-index: 9999 !important; /* 确保气泡在最上层 */
    min-width: 200px;
    max-width: 400px;
    padding: 12px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 15%);
  }
}
</style>

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