<!-- eslint-disable unicorn/no-invalid-remove-event-listener -->
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, onUpdated, ref } from 'vue'

import MdKatex from '@vscode/markdown-it-katex'
import hljs from 'highlight.js'
import MarkdownIt from 'markdown-it'
import MdLinkAttributes from 'markdown-it-link-attributes'
import MdMermaid from 'mermaid-it-markdown'

import { copy } from '#/utils/copy'

import languages from './languages.json'

import 'highlight.js/styles/atom-one-dark.min.css'

interface Props {
  asRawText?: boolean
  error?: boolean
  inversion?: boolean
  text?: string
}

const props = defineProps<Props>()

const textRef = ref<HTMLElement>()

const mdi = new MarkdownIt({
  html: true,
  linkify: true,
  highlight(code, language) {
    const validLang = !!(language && hljs.getLanguage(language))
    if (validLang) {
      const lang = language ?? ''
      return highlightBlock(
        hljs.highlight(code, { language: lang }).value,
        lang,
      )
    }
    return highlightBlock(hljs.highlightAuto(code).value, '')
  },
})

mdi
  .use(MdLinkAttributes, { attrs: { target: '_blank', rel: 'noopener' } })
  .use(MdKatex)
  .use(MdMermaid)

const text = computed(() => {
  const value = props.text ?? ''
  if (!props.asRawText) {
    // 对数学公式进行处理，自动添加 $$ 符号
    // console.log('value', value)
    // const escapedText = escapeBrackets(escapeDollarNumber(value))
    // console.log('escapedText', escapedText)
    return mdi.render(value)
  }
  return value
})

function highlightBlock(str: string, lang?: string) {
  // 处理语言名称
  const originLang = (lang?.trim().toLowerCase() as string) || 'txt'
  let language = (languages as any)[originLang]
  if (!language) {
    language =
      originLang.length === 1
        ? originLang.toUpperCase()
        : originLang.charAt(0).toUpperCase() + originLang.slice(1)
  }
  // 处理行号
  str = str
    .trim()
    .split('\n')
    .map((line) => `<span class="hljs-line">${line}</span>`)
    .join('\n')
  return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${language}</span><span class="code-block-header__copy">复制代码</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
}

function addCopyEvents() {
  if (textRef.value) {
    const copyBtn = textRef.value.querySelectorAll('.code-block-header__copy')
    copyBtn.forEach((btn) => {
      btn.addEventListener('click', () => {
        copy(btn.parentElement?.nextElementSibling?.textContent)
      })
    })
  }
}

function removeCopyEvents() {
  if (textRef.value) {
    const copyBtn = textRef.value.querySelectorAll('.code-block-header__copy')
    copyBtn.forEach((btn) => {
      btn.removeEventListener('click', () => {})
    })
  }
}

function escapeDollarNumber(text: string) {
  let escapedText = ''

  for (let i = 0; i < text.length; i += 1) {
    let char = text[i]
    const nextChar = text[i + 1] || ' '

    if (char === '$' && nextChar >= '0' && nextChar <= '9')
      char = String.raw`\$`

    escapedText += char
  }

  return escapedText
}

function escapeBrackets(text: string) {
  const pattern =
    /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)/g
  return text.replaceAll(
    pattern,
    (match, codeBlock, squareBracket, roundBracket) => {
      if (codeBlock) return codeBlock
      else if (squareBracket) return `$$${squareBracket}$$`
      else if (roundBracket) return `$${roundBracket}$`
      return match
    },
  )
}

function escapeAllBrackets(text: string) {
  const pattern =
    /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)/g
  return text.replaceAll(pattern, '')
}

onMounted(() => {
  addCopyEvents()
})

onUpdated(() => {
  addCopyEvents()
})

onUnmounted(() => {
  removeCopyEvents()
})
</script>

<template>
  <div class="text-black">
    <div ref="textRef" class="break-words leading-relaxed">
      <div v-if="!inversion">
        <div v-if="!asRawText" class="markdown-body" v-html="text"></div>
        <div v-else class="whitespace-pre-wrap" v-text="text"></div>
      </div>
      <div v-else class="whitespace-pre-wrap" v-text="text"></div>
    </div>
  </div>
</template>

<style lang="scss">
@use './index.scss' as *;
</style>
