<template>
  <view class="im-parse" :class="customClass" :style="customStyle">
    <!-- 解析模式 -->
    <template v-if="mode === 'html' && content">
      <rich-text v-if="useRichText" :id="richTextId" :nodes="dom.nodesToHtml(parsedNodes)" />
      <view v-else class="im-parse__html" v-html="content" @tap="handleHtmlTap" />
    </template>

    <!-- 文本模式 -->
    <template v-else-if="mode === 'text' && content">
      <text class="im-parse__text" :style="textStyle" @tap="handleTextTap">
        {{ processedText }}
      </text>
    </template>

    <!-- Markdown 模式 -->
    <template v-else-if="mode === 'markdown' && content">
      <view class="im-parse__markdown">
        <template v-for="(node, index) in markdownNodes" :key="index">
          <!-- 标题 -->
          <view v-if="node.type === 'heading'" class="im-parse__heading" :class="`im-parse__heading--${node.depth}`">
            <text>{{ node.text }}</text>
          </view>

          <!-- 段落 -->
          <view v-else-if="node.type === 'paragraph'" class="im-parse__paragraph">
            <text>{{ node.text }}</text>
          </view>

          <!-- 列表 -->
          <view v-else-if="node.type === 'list'" class="im-parse__list"
            :class="{ 'im-parse__list--ordered': node.ordered }">
            <view v-for="(item, itemIndex) in node.items" :key="itemIndex" class="im-parse__list-item">
              <view class="im-parse__list-marker">
                {{ node.ordered ? `${Number(itemIndex) + 1}.` : '•' }}
              </view>
              <text class="im-parse__list-text">{{ item }}</text>
            </view>
          </view>

          <!-- 引用 -->
          <view v-else-if="node.type === 'blockquote'" class="im-parse__blockquote">
            <text>{{ node.text }}</text>
          </view>

          <!-- 代码块 -->
          <view v-else-if="node.type === 'code'" class="im-parse__code-block">
            <text class="im-parse__code-text">{{ node.text }}</text>
          </view>
        </template>
      </view>
    </template>

    <!-- JSON 模式 -->
    <template v-else-if="mode === 'json' && content">
      <view class="im-parse__json">
        <pre class="im-parse__json-pre">{{ formattedJson }}</pre>
      </view>
    </template>

    <!-- 默认插槽 -->
    <slot v-if="!content" name="default"></slot>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import type { LinkData, ParseProps, ParseEmits } from "../../types/components/parse";
import { emojiHelper, dom } from '../../index'

// 定义 Props 默认值
const props = withDefaults(defineProps<ParseProps>(), {
  content: '',
  modelValue: '',

  options: () => ({
    enableLinks: true,
    openExternalInNewWindow: true,
    parseEmail: false,
    parsePhone: false
  }),

  mode: 'html',
  encoding: 'utf-8',

  maxLength: 0,
  ellipsis: '...',
  lines: 0,

  useRichText: true,
  space: 'ensp',
  filterTags: () => ['script', 'style', 'iframe', 'object', 'embed'],
  allowTags: () => [],
  allowAttributes: () => ({}),
  allowDomains: () => [],

  customClass: '',
  customStyle: () => ({}),
  textStyle: () => ({}),

  autolink: true,
  emoji: false,
  highlight: false,
  lazyLoad: false,
  errorFallback: '解析失败',

  preventDefault: false
})

// 定义 Emit
const emit = defineEmits<ParseEmits>()

// 响应式状态
const richTextId = ref('richTextId' + new Date().getTime())
const parsedNodes = ref<any[]>([])
const markdownNodes = ref<any[]>([])
const lastError = ref<Error | null>(null)
const extractedLinks = ref<Array<{ id: string, data: LinkData }>>([]) // 提取的链接数据

// 计算内容
const computedContent = computed(() => {
  return props.modelValue || props.content
})

// 解码内容
const decodedContent = computed(() => {
  const content = computedContent.value
  if (!content) return ''

  try {
    switch (props.encoding) {
      case 'base64':
        return atob(content)
      case 'url':
        return decodeURIComponent(content)
      case 'utf-8':
      default:
        return content
    }
  } catch (error) {
    console.error('解码失败:', error)
    return content
  }
})

// 处理文本内容
const processedText = computed(() => {
  let text = decodedContent.value

  // 处理长度限制
  if (props.maxLength > 0 && text.length > props.maxLength) {
    text = text.substring(0, props.maxLength) + props.ellipsis
  }

  // 自动链接
  if (props.autolink) {
    text = autoLink(text)
  }

  // 表情符号
  if (props.emoji || (emojiHelper as any).containEmoji(text)) {
    text = parseEmoji(text)
  }

  // 语法高亮
  if (props.highlight) {
    text = highlightText(text)
  }

  return text
})

// 生命周期
onMounted(() => {
  initParse()
})

// 解析 HTML 节点
const parseHtml = async (html: string) => {
  if (!html) return []

  try {
    // 简单的 HTML 解析器
    const nodes = parseHtmlToNodes(html)
    emit('parse-success', nodes)
    return nodes
  } catch (error) {
    lastError.value = error as Error
    emit('parse-error', error as Error)
    return [{ type: 'text', text: props.errorFallback }]
  }
}

// 解析 Markdown
const parseMarkdown = (markdown: string) => {
  if (!markdown) return []

  try {
    const nodes = parseMarkdownToNodes(markdown)
    emit('parse-success', nodes)
    return nodes
  } catch (error) {
    lastError.value = error as Error
    emit('parse-error', error as Error)
    return [{ type: 'paragraph', text: props.errorFallback }]
  }
}

// 格式化 JSON
const formattedJson = computed(() => {
  try {
    const content = decodedContent.value
    if (!content) return ''

    const obj = JSON.parse(content)
    return JSON.stringify(obj, null, 2)
  } catch (error) {
    return props.errorFallback
  }
})

// 简单的 HTML 解析器
const parseHtmlToNodes = (html: string): any[] => {
  const nodes: any[] = []

  // 移除危险标签
  let safeHtml = html
  props.filterTags.forEach(tag => {
    const regex = new RegExp(`<${tag}[^>]*>.*?</${tag}>`, 'gis')
    safeHtml = safeHtml.replace(regex, '')
  })

  // 简化的解析逻辑
  // 实际项目中可以使用更完善的 HTML 解析库
  const textMatch = safeHtml.match(/>(.*?)</)
  if (textMatch) {
    nodes.push({
      type: 'text',
      text: textMatch[1]
    })
  }

  return nodes
}

// 简单的 Markdown 解析器
const parseMarkdownToNodes = (markdown: string): any[] => {
  const nodes: any[] = []
  const lines = markdown.split('\n')

  for (let i = 0; i < lines.length; i++) {
    const line = lines[i].trim()

    if (!line) continue

    // 标题
    const headingMatch = line.match(/^(#{1,6})\s+(.+)$/)
    if (headingMatch) {
      nodes.push({
        type: 'heading',
        depth: headingMatch[1].length,
        text: headingMatch[2]
      })
      continue
    }

    // 列表项
    const listMatch = line.match(/^[\*\-\+]\s+(.+)$/)
    if (listMatch) {
      // 查找连续的列表项
      const items = [listMatch[1]]
      while (i + 1 < lines.length && lines[i + 1].match(/^[\*\-\+]\s/)) {
        i++
        items.push(lines[i].replace(/^[\*\-\+]\s+/, ''))
      }

      nodes.push({
        type: 'list',
        ordered: false,
        items
      })
      continue
    }

    // 数字列表
    const orderedListMatch = line.match(/^\d+\.\s+(.+)$/)
    if (orderedListMatch) {
      const items = [orderedListMatch[1]]
      while (i + 1 < lines.length && lines[i + 1].match(/^\d+\.\s/)) {
        i++
        items.push(lines[i + 1].replace(/^\d+\.\s+/, ''))
      }

      nodes.push({
        type: 'list',
        ordered: true,
        items
      })
      continue
    }

    // 引用
    if (line.startsWith('> ')) {
      nodes.push({
        type: 'blockquote',
        text: line.substring(2)
      })
      continue
    }

    // 代码块
    if (line.startsWith('```')) {
      const language = line.substring(3).trim() || ''
      const codeLines = []

      while (i + 1 < lines.length && !lines[i + 1].startsWith('```')) {
        i++
        codeLines.push(lines[i])
      }
      i++ // 跳过结束的 ```

      nodes.push({
        type: 'code',
        language,
        text: codeLines.join('\n')
      })
      continue
    }

    // 普通段落
    nodes.push({
      type: 'paragraph',
      text: line
    })
  }

  return nodes
}

// 自动链接
const autoLink = (text: string): string => {
  const urlRegex = /(https?:\/\/[^\s]+)/g
  return text.replace(urlRegex, '<a href="$1">$1</a>')
}

// 解析表情符号
const parseEmoji = (text: string): string => {
  const emojiMap: Record<string, string> = {
    ':)': '😊',
    ':(': '😔',
    ':D': '😃',
    ';)': '😉',
    ':P': '😛',
    ':O': '😮',
    ':*': '😘',
    '<3': '❤️'
  }

  let result = text
  Object.keys(emojiMap).forEach(key => {
    const k = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    result = result.replace(new RegExp(k, 'g'), emojiMap[k])
  })

  return result
}

// 文本高亮
const highlightText = (text: string): string => {
  // 简单的关键词高亮
  const keywords = ['important', 'urgent', 'note', 'warning', 'info']
  let result = text

  keywords.forEach(keyword => {
    const regex = new RegExp(`\\b${keyword}\\b`, 'gi')
    result = result.replace(regex, `<span class="highlight">${keyword}</span>`)
  })

  return result
}

// 处理链接点击
const handleLinkPress = (event: any) => {
  const url = event.detail?.href
  if (url) {
    emit('linkpress', url)

    if (props.preventDefault) {
      return
    }

    // 检查域名是否允许
    if (props.allowDomains.length > 0) {
      try {
        const domain = new URL(url).hostname
        if (!props.allowDomains.includes(domain)) {
          uni.showToast({
            title: '禁止访问此域名',
            icon: 'none'
          })
          return
        }
      } catch (error) {
        console.error('解析URL失败:', error)
      }
    }

    // 跳转到链接
    uni.navigateTo({
      url: `/pages/webview/webview?url=${encodeURIComponent(url)}`
    })
  }
}


/**
 * 解析 HTML 字符串并提取链接
 */
const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } => {
  const links: LinkData[] = []
  let linkIndex = 0

  // 使用正则表达式匹配 a 标签
  const linkRegex = /<a\s+(?:[^>]*?\s+)?href=(["'])(.*?)\1[^>]*?>(.*?)<\/a>/gi

  // 替换链接为可点击元素
  const processedHtml = html.replace(linkRegex, (match, quote, url, text) => {
    // 清理 URL
    const cleanUrl = url.trim()
    const cleanText = text.replace(/<[^>]*>/g, '').trim()

    // 检查是否为外部链接
    const isExternal = /^(https?:)?\/\//i.test(cleanUrl) &&
      !cleanUrl.includes(location.hostname)

    const linkData: LinkData = {
      url: cleanUrl,
      text: cleanText,
      isExternal
    }

    links.push(linkData)

    // 生成唯一的 ID
    const linkId = `link-${linkIndex++}`

    // 替换为可点击的富文本节点
    return `<span 
              data-link-id="${linkId}" 
              data-link-url="${encodeURIComponent(cleanUrl)}"
              style="color: #007AFF; text-decoration: underline;"
              class="im-parse-link"
            >${cleanText}</span>`
  })

  // 解析电子邮件（如果启用）
  let finalHtml = processedHtml
  if (props.options?.parseEmail) {
    const emailRegex = /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g
    finalHtml = finalHtml.replace(emailRegex, (email) => {
      const emailId = `email-${linkIndex++}`
      const linkData: LinkData = {
        url: `mailto:${email}`,
        text: email,
        isExternal: false
      }
      links.push(linkData)

      return `<span 
                data-link-id="${emailId}" 
                data-link-url="mailto:${email}"
                style="color: #007AFF; text-decoration: underline;"
                class="im-parse-email"
              >${email}</span>`
    })
  }

  // 解析电话号码（如果启用）
  if (props.options?.parsePhone) {
    const phoneRegex = /(\+?\d[\d\s\-\(\)]{7,}\d)/g
    finalHtml = finalHtml.replace(phoneRegex, (phone) => {
      const cleanPhone = phone.replace(/[\s\-\(\)]/g, '')
      const phoneId = `phone-${linkIndex++}`
      const linkData: LinkData = {
        url: `tel:${cleanPhone}`,
        text: phone,
        isExternal: false
      }
      links.push(linkData)

      return `<span 
                data-link-id="${phoneId}" 
                data-link-url="tel:${cleanPhone}"
                style="color: #007AFF; text-decoration: underline;"
                class="im-parse-phone"
              >${phone}</span>`
    })
  }

  // 提取链接信息到响应式数组
  extractedLinks.value = links.map((link, index) => ({
    id: `link-${index}`,
    data: link
  }))

  // 返回解析后的节点（这里简化处理，实际可能需要更复杂的 HTML 解析）
  return {
    nodes: [{
      name: 'div',
      attrs: {
        class: 'im-parse-content'
      },
      children: [{
        type: 'text',
        text: finalHtml
      }]
    }],
    links
  }
}

/**
 * 处理链接点击
 */
const handleLinkClick = (linkData: LinkData, event?: Event) => {
  // 触发自定义事件
  emit('link-click', linkData, event)

  // 调用用户提供的回调
  if (props.options?.onLinkClick) {
    props.options.onLinkClick(linkData, event)
  }

  // 执行默认行为（在 uniapp 中）
  handleDefaultLinkBehavior(linkData)
}

/**
 * 处理默认链接行为
 */
const handleDefaultLinkBehavior = (linkData: LinkData) => {
  const { url, isExternal } = linkData

  // 处理邮件链接
  if (url.startsWith('mailto:')) {
    uni.makePhoneCall({
      phoneNumber: url.replace('mailto:', ''),
      fail: () => {
        uni.showToast({
          title: '无法打开邮件客户端',
          icon: 'none'
        })
      }
    })
    return
  }

  // 处理电话链接
  if (url.startsWith('tel:')) {
    uni.makePhoneCall({
      phoneNumber: url.replace('tel:', ''),
      fail: () => {
        uni.showToast({
          title: '无法拨打电话',
          icon: 'none'
        })
      }
    })
    return
  }

  // 处理网页链接
  if (/^(https?:)?\/\//i.test(url)) {
    // 在 uniapp 中打开网页
    uni.navigateTo({
      url: `/pages/webview/webview?url=${encodeURIComponent(url)}`,
      fail: () => {
        // 如果页面不存在，尝试使用浏览器打开
        if (isExternal && props.options?.openExternalInNewWindow) {
          plus.runtime.openURL(url, (err) => {
            uni.showToast({
              title: '无法打开链接',
              icon: 'none'
            })
          })
        }
      }
    })
  } else {
    // 内部链接
    uni.navigateTo({
      url: url,
      fail: () => {
        uni.showToast({
          title: '页面不存在',
          icon: 'none'
        })
      }
    })
  }
}

/**
 * 处理富文本内部点击事件
 */
const handleRichTextItemClick = (event: any) => {
  console.log('click', event)
  const { dataset } = event.detail || {}

  if (dataset && dataset.linkId) {
    const linkItem = extractedLinks.value.find(item => item.id === dataset.linkId)
    if (linkItem) {
      // 解码 URL
      const decodedUrl = decodeURIComponent(dataset.linkUrl || linkItem.data.url)
      const linkData = {
        ...linkItem.data,
        url: decodedUrl
      }

      handleLinkClick(linkData, event)
    }
  }
}

/**
 * 初始化解析
 */
const initParse = () => {
  if (!props.content) {
    parsedNodes.value = []
    return
  }

  try {
    const result = parseHtmlWithLinks(props.content)
    parsedNodes.value = result.nodes
  } catch (error) {
    console.error('解析内容失败:', error)
    // 出错时显示原始文本
    parsedNodes.value = [{
      name: 'div',
      attrs: {
        class: 'im-parse-error'
      },
      children: [{
        type: 'text',
        text: props.content
      }]
    }]
  }
}

// 处理 HTML 点击
const handleHtmlTap = (event: any) => {
  emit('click', event)
}

// 处理文本点击
const handleTextTap = (event: any) => {
  emit('click', event)
}

// 图片加载错误
const handleImageError = (src: string, error: Error) => {
  emit('imageerror', src, error)
}

// 图片加载成功
const handleImageLoad = (src: string) => {
  emit('imageload', src)
}

// 重新解析
const reparse = async () => {
  lastError.value = null

  if (props.mode === 'html') {
    // parsedNodes.value = await parseHtml(decodedContent.value)
    initParse()
  } else if (props.mode === 'markdown') {
    markdownNodes.value = parseMarkdown(decodedContent.value)
  }
}

// 获取解析结果
const getParsedResult = () => {
  if (props.mode === 'html') {
    return parsedNodes.value
  } else if (props.mode === 'markdown') {
    return markdownNodes.value
  } else if (props.mode === 'json') {
    try {
      return JSON.parse(decodedContent.value)
    } catch {
      return null
    }
  }
  return processedText.value
}

// 清空内容
const clear = () => {
  parsedNodes.value = []
  markdownNodes.value = []
  lastError.value = null
  emit('update:modelValue', '')
}


// 监听内容变化
watch(() => computedContent.value, async (newContent) => {
  if (newContent) {
    await reparse()
  } else {
    clear()
  }
}, { immediate: true })

watch(() => props.content, () => {
  initParse()
})

watch(() => props.options, () => {
  initParse()
}, { deep: true })

// 暴露方法
defineExpose({
  reparse,
  getParsedResult,
  clear,
  getError: () => lastError.value
})
</script>

<style lang="scss" scoped>
.im-parse {
  width: 100%;
  word-break: break-word;
  line-height: 1.6;

  &__html {

    // HTML 样式
    :deep(img) {
      max-width: 100%;
      height: auto;
      vertical-align: middle;
    }

    :deep(a) {
      color: #409eff;
      text-decoration: none;

      &:active {
        opacity: 0.7;
      }
    }

    :deep(p) {
      margin: 16rpx 0;
    }

    :deep(h1),
    :deep(h2),
    :deep(h3),
    :deep(h4),
    :deep(h5),
    :deep(h6) {
      margin: 32rpx 0 16rpx;
      font-weight: bold;
    }

    :deep(h1) {
      font-size: 40rpx;
    }

    :deep(h2) {
      font-size: 36rpx;
    }

    :deep(h3) {
      font-size: 32rpx;
    }

    :deep(h4) {
      font-size: 28rpx;
    }

    :deep(ul),
    :deep(ol) {
      margin: 16rpx 0;
      padding-left: 48rpx;
    }

    :deep(li) {
      margin: 8rpx 0;
    }

    :deep(blockquote) {
      margin: 16rpx 0;
      padding: 16rpx 32rpx;
      background-color: #f5f5f5;
      border-left: 8rpx solid #ddd;
      color: #666;
    }

    :deep(code) {
      padding: 4rpx 8rpx;
      background-color: #f5f5f5;
      border-radius: 4rpx;
      font-family: Consolas, Monaco, 'Courier New', monospace;
      font-size: 90%;
    }

    :deep(pre) {
      margin: 16rpx 0;
      padding: 24rpx;
      background-color: #f5f5f5;
      border-radius: 8rpx;
      overflow-x: auto;

      code {
        padding: 0;
        background-color: transparent;
      }
    }

    :deep(table) {
      width: 100%;
      border-collapse: collapse;
      margin: 16rpx 0;

      th,
      td {
        padding: 16rpx;
        border: 2rpx solid #ddd;
        text-align: left;
      }

      th {
        background-color: #f5f5f5;
        font-weight: bold;
      }
    }
  }

  &__text {
    display: block;
    width: 100%;
  }

  &__markdown {
    .highlight {
      background-color: #fffbe6;
      padding: 2rpx 6rpx;
      border-radius: 4rpx;
      color: #d48806;
    }
  }

  &__heading {
    margin: 32rpx 0 16rpx;
    font-weight: bold;

    &--1 {
      font-size: 40rpx;
    }

    &--2 {
      font-size: 36rpx;
    }

    &--3 {
      font-size: 32rpx;
    }

    &--4 {
      font-size: 28rpx;
    }

    &--5 {
      font-size: 26rpx;
    }

    &--6 {
      font-size: 24rpx;
    }
  }

  &__paragraph {
    margin: 16rpx 0;
  }

  &__list {
    margin: 16rpx 0;

    &--ordered {
      padding-left: 48rpx;
      list-style-type: decimal;
    }

    &:not(.im-parse__list--ordered) {
      padding-left: 48rpx;
      list-style-type: disc;
    }
  }

  &__list-item {
    display: flex;
    align-items: flex-start;
    margin: 8rpx 0;
  }

  &__list-marker {
    margin-right: 16rpx;
    min-width: 32rpx;
    text-align: right;
  }

  &__list-text {
    flex: 1;
  }

  &__blockquote {
    margin: 16rpx 0;
    padding: 16rpx 32rpx;
    background-color: #f5f5f5;
    border-left: 8rpx solid #ddd;
    color: #666;
  }

  &__code-block {
    margin: 16rpx 0;
    padding: 24rpx;
    background-color: #f5f5f5;
    border-radius: 8rpx;
    overflow-x: auto;
  }

  &__code-text {
    font-family: Consolas, Monaco, 'Courier New', monospace;
    font-size: 90%;
    white-space: pre;
  }

  &__json {
    width: 100%;
    overflow-x: auto;
  }

  &__json-pre {
    margin: 0;
    padding: 24rpx;
    background-color: #f5f5f5;
    border-radius: 8rpx;
    font-family: Consolas, Monaco, 'Courier New', monospace;
    font-size: 90%;
    white-space: pre;
  }
}

// 多行省略
.im-parse--ellipsis {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>