import { Marked } from 'marked'
import { markedHighlight } from 'marked-highlight'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import mermaid from 'mermaid'
import panzoom from 'panzoom'
import { nanoid } from 'nanoid'
import markedKatex, { type MarkedKatexOptions } from 'marked-katex-extension'
import i18n from '@/locales'

const t = i18n.global.t

const katexOptions: MarkedKatexOptions = {
  throwOnError: false,
  displayMode: true,
  nonStandard: true,
  output: 'html',
}

// Mermaid初始化
mermaid.initialize({
  startOnLoad: false,
  htmlLabels: true,
  suppressErrorRendering: true,
  theme: 'default',
  securityLevel: 'loose',
  fontFamily: 'Microsoft YaHei UI',
  altFontFamily: 'Microsoft YaHei UI',
  fontSize: 14,
  themeVariables: {
    textColor: '#333',
    pie1: '#94d4c0',
    pie2: '#fdaf91',
    pie3: '#afbddb',
    pie4: '#eeadd5',
    pieSectionTextSize: '16px',
    pieLegendTextSize: '16px',
    pieTitleTextSize: '24px',
  },
  pie: {
    textPosition: 0.6,
  },
  flowchart: {
    useMaxWidth: false,
  },
})

// 创建Mermaid扩展
const createMermaidExtension = () => ({
  name: 'mermaid',
  level: 'block' as const,
  start(src: string) {
    return src.match(/^```mermaid/)?.index
  },
  tokenizer(src: string) {
    const match = src.match(/^```mermaid\n([\s\S]*?)\n```/)
    if (match) {
      return {
        type: 'mermaid',
        raw: match[0],
        text: match[1].trim(),
      }
    }
    return undefined
  },
  renderer(token: { text?: string }) {
    return `<pre class="mermaid">${token.text}</pre>`
  },
})

const walkTokens = async (token: any) => {
  switch (token.type) {
    case 'mermaid': {
      try {
        const mermaidId = `mermaid-${nanoid()}`
        const { svg } = await mermaid.render(mermaidId, token.text)

        const tempDiv = document.createElement('div')
        tempDiv.innerHTML = `<div class="mermaid-viewer">${svg}</div>`

        const svgEl = tempDiv.querySelector('.mermaid-viewer svg')
        if (svgEl) {
          svgEl.setAttribute('height', '100%')
          svgEl.setAttribute('width', '100%')
        }

        token.text = tempDiv.innerHTML
      } catch (error) {
        token.text = `<div class="mermaid-error">
            <div class="render-error-icon-container"></div>
            <span>${t('common_module.mermaid_render_error')}</span>
          </div>`
      }
      break
    }
  }
}

export function initMermaidPanzoom() {
  setTimeout(() => {
    const mermaidViewers = document.querySelectorAll('.mermaid-viewer')
    mermaidViewers.forEach((viewer) => {
      const svgEl = viewer.querySelector('svg')
      if (svgEl) {
        panzoom(svgEl as SVGElement, {
          maxZoom: 5,
          minZoom: 0.2,
          bounds: true,
          boundsPadding: 0.1,
        })
      }
    })
  }, 0)
}

export function createMarkedInst() {
  return new Marked()
    .use({
      gfm: true,
      async: true,
      breaks: true,
      extensions: [createMermaidExtension()],
    })
    .use(
      markedHighlight({
        emptyLangClass: 'hljs',
        langPrefix: 'hljs code-container-wrapper language-',
        highlight(code, lang, _info) {
          if (lang === 'mermaid') {
            return `<div class="mermaid-rendering-container">
              <div class="mermaid-rendering-content">${t('common_module.mermaid_rendering')}</div>
            </div>`
          }

          const language = hljs.getLanguage(lang) ? lang : 'plaintext'

          // return hljs.highlight(code, { language }).value
          const str = hljs.highlight(code, { language }).value

          // return `<div class="code-render-container"><div class="code-operation-bar-container"><span class="language">${language}</span><span><span class="code-copy-btn iconfont icon-fuzhi"></span><span class="fold-btn iconfont icon-left"></span></span></div><pre class="code-render-inner"><code>${str}</code></pre></div>`

          return (
            '<div class="code-render-container">' +
            '<div class="code-operation-bar-container">' +
            `<span class="language">${language}</span><span><span class="code-copy-btn iconfont icon-fuzhi"></span><span class="fold-btn iconfont icon-left"></span></span>` +
            '</div>' +
            `<div class="code-render-wrapper"><pre class="code-render-inner"><code>${str}</code></pre></div>` +
            '</div>'
          )
        },
      }),
    )
    .use(markedKatex(katexOptions))
    .use({ walkTokens, async: true })
    .use({
      hooks: {
        preprocess(markdown: string) {
          /**
           * 1. 将 \(...\) 和 \\(...\\) 转为 $...$ 以支持行内公式
           * 2. 将 \[...\] 和 \\[...\\]  转为 $$...$$ 以支持块级公式
           */

          const katexTextReplace = markdown
            .replace(/\\\\\(|\\\\\)|\\\(|\\\)/g, '$')
            .replace(/\\\\\[|\\\\\]|\\\[|\\\]/g, '$$$$')

          return katexTextReplace
        },
        postprocess(html: string) {
          initMermaidPanzoom()
          return getSanitizedHtml(html)
        },
      },
    })
}

// 获取净化HTML, 排除Mermaid render的svg标签
function getSanitizedHtml(html: string) {
  const mermaidElementRegex = /<div class="mermaid-viewer"><svg(.*?)>(.*?)<\/svg><\/div>/gs
  const mermaidObjects: { placeholder: string; content: string }[] = []
  let processedHtml = html
  let match: RegExpExecArray | null = null
  let i = 0

  while ((match = mermaidElementRegex.exec(html)) !== null) {
    const fullMatch = match[0]

    const placeholder = `MERMAID_PLACEHOLDER_${i}`
    mermaidObjects.push({ placeholder, content: fullMatch })

    processedHtml = processedHtml.replace(fullMatch, placeholder)
    i++
  }

  const sanitizedHtmlWithoutMermaid = DOMPurify.sanitize(processedHtml)

  let sanitizedHtml = sanitizedHtmlWithoutMermaid
  for (const mermaidItem of mermaidObjects) {
    sanitizedHtml = sanitizedHtml.replace(mermaidItem.placeholder, mermaidItem.content)
  }

  return sanitizedHtml
}

export function markdownParser(markdown: string) {
  return createMarkedInst().parse(markdown)
}
