import { App, Directive } from 'vue'
import hljs from 'highlight.js'
import { ElMessage } from 'element-plus'

/**
 * 高亮代码
 * 插入行号、添加复制按钮、分片处理代码块，解决大数据量一次写入卡顿问题
 * 支持动态内容监听，确保所有代码块都能被正确处理
 */

// 高亮代码
function highlightCode(block: HTMLElement) {
  hljs.highlightElement(block)
}

// 插入行号
function insertLineNumbers(block: HTMLElement) {
  const lines = block.innerHTML.split('\n')
  const numberedLines = lines
    .map((line, index) => {
      return `<span class="line-number">${index + 1}</span> ${line}`
    })
    .join('\n')
  block.innerHTML = numberedLines
}

// 添加复制按钮：调整 DOM 结构，将代码部分包裹在 .code-wrapper 内
function addCopyButton(block: HTMLElement) {
  const copyButton = document.createElement('i')
  copyButton.className = 'copy-button iconfont-sys'
  copyButton.innerHTML = '&#xe7b2;'
  copyButton.onclick = () => {
    // 过滤掉行号，只复制代码内容
    const codeContent = block.innerText.replace(/^\d+\s+/gm, '')
    navigator.clipboard.writeText(codeContent).then(() => {
      ElMessage.success('复制成功')
    })
  }

  const preElement = block.parentElement
  if (preElement) {
    let codeWrapper: HTMLElement
    // 如果代码块还没有被包裹，则创建包裹容器
    if (!block.parentElement.classList.contains('code-wrapper')) {
      codeWrapper = document.createElement('div')
      codeWrapper.className = 'code-wrapper'
      preElement.replaceChild(codeWrapper, block)
      codeWrapper.appendChild(block)
    } else {
      codeWrapper = block.parentElement
    }
    // 将复制按钮添加到 pre 元素（而非 codeWrapper 内），这样它不会随滚动条滚动
    preElement.appendChild(copyButton)
  }
}

// 检查代码块是否已经被处理过
function isBlockProcessed(block: HTMLElement): boolean {
  return (
    block.hasAttribute('data-highlighted') ||
    !!block.querySelector('.line-number') ||
    !!block.parentElement?.querySelector('.copy-button')
  )
}

// 标记代码块为已处理
function markBlockAsProcessed(block: HTMLElement) {
  block.setAttribute('data-highlighted', 'true')
}

// 处理单个代码块
function processBlock(block: HTMLElement) {
  if (isBlockProcessed(block)) {
    return
  }

  try {
    highlightCode(block)
    insertLineNumbers(block)
    addCopyButton(block)
    markBlockAsProcessed(block)
  } catch (error) {
    console.warn('处理代码块时出错:', error)
  }
}

// 查找并处理所有代码块
function processAllCodeBlocks(el: HTMLElement) {
  const blocks = Array.from(el.querySelectorAll<HTMLElement>('pre code'))
  const unprocessedBlocks = blocks.filter((block) => !isBlockProcessed(block))

  if (unprocessedBlocks.length === 0) {
    return
  }

  if (unprocessedBlocks.length <= 10) {
    // 如果代码块数量少于等于10，直接处理所有代码块
    unprocessedBlocks.forEach((block) => processBlock(block))
  } else {
    // 定义每次处理的代码块数
    const batchSize = 10
    let currentIndex = 0

    const processBatch = () => {
      const batch = unprocessedBlocks.slice(currentIndex, currentIndex + batchSize)

      batch.forEach((block) => {
        processBlock(block)
      })

      // 更新索引并继续处理下一批
      currentIndex += batchSize
      if (currentIndex < unprocessedBlocks.length) {
        // 使用 requestAnimationFrame 确保下一帧再处理
        requestAnimationFrame(processBatch)
      }
    }

    // 开始处理第一批代码块
    processBatch()
  }
}

// 重试处理函数
function retryProcessing(el: HTMLElement, maxRetries: number = 3, delay: number = 200) {
  let retryCount = 0

  const tryProcess = () => {
    processAllCodeBlocks(el)

    // 检查是否还有未处理的代码块
    const remainingBlocks = Array.from(el.querySelectorAll<HTMLElement>('pre code')).filter(
      (block) => !isBlockProcessed(block)
    )

    if (remainingBlocks.length > 0 && retryCount < maxRetries) {
      retryCount++
      setTimeout(tryProcess, delay * retryCount) // 递增延迟
    }
  }

  tryProcess()
}

// 代码高亮、插入行号、复制按钮
const highlightDirective: Directive<HTMLElement> = {
  mounted(el: HTMLElement) {
    // 立即尝试处理一次
    processAllCodeBlocks(el)

    // 延迟处理，确保 v-html 内容已经渲染
    setTimeout(() => {
      retryProcessing(el)
    }, 100)

    // 使用 MutationObserver 监听 DOM 变化
    const observer = new MutationObserver((mutations) => {
      let hasNewCodeBlocks = false

      mutations.forEach((mutation) => {
        if (mutation.type === 'childList') {
          mutation.addedNodes.forEach((node) => {
            if (node.nodeType === Node.ELEMENT_NODE) {
              const element = node as HTMLElement
              // 检查新添加的节点是否包含代码块
              if (element.tagName === 'PRE' || element.querySelector('pre code')) {
                hasNewCodeBlocks = true
              }
            }
          })
        }
      })

      if (hasNewCodeBlocks) {
        // 延迟处理新添加的代码块
        setTimeout(() => {
          processAllCodeBlocks(el)
        }, 50)
      }
    })

    // 开始观察
    observer.observe(el, {
      childList: true,
      subtree: true
    })

    // 将 observer 存储到元素上，以便在 unmounted 时清理
    ;(el as any)._highlightObserver = observer
  },

  updated(el: HTMLElement) {
    // 当组件更新时，重新处理代码块
    setTimeout(() => {
      processAllCodeBlocks(el)
    }, 50)
  },

  unmounted(el: HTMLElement) {
    // 清理 MutationObserver
    const observer = (el as any)._highlightObserver
    if (observer) {
      observer.disconnect()
      delete (el as any)._highlightObserver
    }
  }
}

export function setupHighlightDirective(app: App) {
  app.directive('highlight', highlightDirective)
}
