<!-- eslint-disable unicorn/prefer-ternary -->
<!-- eslint-disable no-cond-assign -->
<!-- eslint-disable unicorn/prefer-string-slice -->
<script setup lang="ts">
import katex from 'katex'

import { initImgPreview } from '#/utils/tool'

import 'katex/dist/katex.min.css'

defineOptions({ name: 'LatexText' })

const props = defineProps<{
  prefix?: any
  text: any
}>()

const regex_dollar = /(\$[^$]+\$)/g
const regex_tag = /(<span data-.+?="[^"]*"><\/span>)/g
// 仅匹配合法 HTML 标签，避免将 $a<b$ 中的 <b 误判为标签并吞掉后续内容
const regex_html = /(<\/?[a-zA-Z][a-zA-Z0-9]*(?:\s+[^>]*)?\s*>)/g

function escapeHtml(text: string) {
  return text
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
}

function addLatexText(list: any[], text: string) {
  list.push({
    isLatex: true,
    content: katex.renderToString(text, { throwOnError: false, strict: false }),
  })
}

function parseLatexDollar(list: any[], text: string) {
  if (!text?.length) return
  const htmlParts = text.split(regex_html)
  for (const htmlPart of htmlParts) {
    if (!htmlPart) continue
    if (htmlPart.startsWith('<')) {
      list.push({ content: htmlPart })
      continue
    }
    const parts = htmlPart.split(regex_dollar)
    for (const part of parts) {
      if (part.startsWith('$') && part.endsWith('$') && part.length > 2) {
        addLatexText(list, part.substring(1, part.length - 1))
      } else if (part) {
        list.push({
          content: escapeHtml(part.replace(/\\([{}])/g, '$1')),
        })
      }
    }
  }
}

function parseLatexTag(list: any[], text: string) {
  if (!text?.length) return
  const parts = text.split(regex_tag)
  if (!parts?.length) return
  for (const part of parts) {
    let match: any
    if (
      part.includes('type="formula"') &&
      (match = part.match(/(?<=data-value=").*?(?=")/))
    ) {
      const text = match[0]
        .replace('\t', String.raw`\t`)
        .replace('\n', String.raw`\n`)
      addLatexText(list, text)
    } else {
      list.push({
        content: part,
      })
    }
  }
}

const renderText = computed(() => {
  const tagList = [] as any[]
  parseLatexTag(tagList, props.text)

  const list = [] as any[]
  for (const item of tagList) {
    if (item.isLatex) {
      list.push(item)
    } else {
      parseLatexDollar(list, item.content)
    }
  }

  let html = ''
  for (const item of list) {
    html += item.content
  }
  html = html.trim()
  const prefix = props.prefix
  if (!prefix) return html
  if (html.startsWith('<p') || html.startsWith('<div')) {
    // 插入到第一个标签后面
    html = html.replace(/^<\w+>/, (match) => {
      return match + prefix
    })
  } else {
    html = prefix + html
  }
  return html
})

const container = ref<HTMLDivElement>()
onMounted(() => {
  initImgPreview(container.value)
})
</script>

<template>
  <div class="latex-text" v-html="renderText" ref="container"></div>
</template>

<style lang="scss" scoped></style>
