<template>
  <div class="mindmap-container">
    <div class="mindmap-actions">
      <span class="mindmap-subtitle" v-if="content">已生成 {{ nodeCount }} 个节点</span>
      <el-dropdown @command="handleDownload">
        <el-button 
          type="primary" 
          size="small"
          class="action-button primary"
        >
          <template #icon>
            <el-icon><Download /></el-icon>
          </template>
          下载
          <el-icon class="el-icon--right"><ArrowDown /></el-icon>
        </el-button>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item command="svg">SVG 格式</el-dropdown-item>
            <el-dropdown-item command="png">PNG 格式</el-dropdown-item>
            <el-dropdown-item command="jpeg">JPEG 格式</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
      <el-button 
        type="default" 
        size="small"
        @click="resetView"
        class="action-button secondary"
      >
        <template #icon>
          <el-icon><Refresh /></el-icon>
        </template>
        重置视图
      </el-button>
    </div>
    <div class="mindmap-content" @wheel.prevent="handleWheel" @click="handleNodeClick">
      <div class="empty-state" v-if="!content">
        <el-icon class="empty-icon"><Document /></el-icon>
        <p class="empty-text">暂无思维导图内容</p>
        <p class="empty-subtext">请先上传并转换文档</p>
      </div>
      <div class="mindmap-loading" v-if="content && isRendering">
        <el-icon class="loading-icon"><Loading /></el-icon>
        <span>正在生成导图...</span>
      </div>
      <svg ref="svgRef" class="markmap-svg" v-show="content"></svg>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch, onUnmounted, nextTick } from 'vue'
import { Download, Refresh, Document, ArrowDown, Loading } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'

// 导入 markmap 相关包
import { Transformer } from 'markmap-lib'
import { Markmap, loadCSS, loadJS } from 'markmap-view'

const props = defineProps({
  content: {
    type: String,
    default: ''
  }
})

const emit = defineEmits<{
  (e: 'node-edit', payload: { oldText: string; newText: string }): void
}>()

const svgRef = ref<SVGElement | null>(null)
let mmInstance: any = null
let renderTimer: number | undefined
const transformer = new Transformer()
const scale = ref(1)
const isRendering = ref(false)

const nodeCount = computed(() => {
  if (!props.content) return 0
  return (props.content.match(/^#{1,6}\s+/gm) || []).length
})

const initMarkmap = async () => {
  if (!svgRef.value) return

  if (!props.content) {
    svgRef.value.innerHTML = ''
    if (mmInstance && typeof mmInstance.destroy === 'function') {
      mmInstance.destroy()
    }
    mmInstance = null
    return
  }

  isRendering.value = true

  try {
    const { root } = transformer.transform(props.content)
    const { styles, scripts } = transformer.getAssets()
    
    if (styles) loadCSS(styles)
    if (scripts) loadJS(scripts)

    await nextTick()

    const initialExpandLevel = nodeCount.value > 80 ? 2 : -1
    
    if (mmInstance) {
      if (typeof mmInstance.setData === 'function') {
        mmInstance.setData(root)
        mmInstance.fit()
      } else {
        mmInstance = Markmap.create(svgRef.value, {
          autoFit: true,
          fitRatio: 0.9,
          initialExpandLevel
        }, root)
      }
    } else {
      mmInstance = Markmap.create(svgRef.value, {
        autoFit: true,
        fitRatio: 0.9,
        initialExpandLevel
      }, root)
    }

    await nextTick()
    svgRef.value?.querySelectorAll('text').forEach((text) => {
      text.setAttribute('data-editable-node', 'true')
    })
  } catch (error) {
    console.error('Error initializing markmap:', error)
    mmInstance = null
  } finally {
    isRendering.value = false
  }
}

// 监听内容变化自动重绘
watch(() => props.content, () => {
  window.clearTimeout(renderTimer)
  renderTimer = window.setTimeout(() => {
    initMarkmap()
  }, 160)
})

onMounted(() => {
  initMarkmap()
  // 窗口缩放时自动调整导图大小
  window.addEventListener('resize', handleResize)
})

onUnmounted(() => {
  window.clearTimeout(renderTimer)
  window.removeEventListener('resize', handleResize)
  if (mmInstance && typeof mmInstance.destroy === 'function') {
    mmInstance.destroy()
  } else if (mmInstance) {
    console.error('mmInstance does not have destroy method:', mmInstance)
  }
})

const handleResize = () => {
  mmInstance?.fit()
}

function downloadBlob(blob: Blob, fileName: string) {
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = fileName
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  URL.revokeObjectURL(url)
}

function createExportSvg() {
  const svg = svgRef.value
  if (!svg) return null

  const svgCopy = svg.cloneNode(true) as SVGElement
  if (!svgCopy.getAttribute('xmlns')) {
    svgCopy.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
  }

  const contentGroup = svg.querySelector('g')
  const bbox = contentGroup
    ? (contentGroup as SVGGElement).getBBox()
    : svg.getBBox()

  const padding = 48
  const width = Math.ceil(Math.max(bbox.width + padding * 2, 320))
  const height = Math.ceil(Math.max(bbox.height + padding * 2, 240))
  const viewBox = `${Math.floor(bbox.x - padding)} ${Math.floor(bbox.y - padding)} ${width} ${height}`

  svgCopy.setAttribute('viewBox', viewBox)
  svgCopy.setAttribute('width', String(width))
  svgCopy.setAttribute('height', String(height))
  svgCopy.querySelectorAll('[style*="cursor"]').forEach((node) => node.removeAttribute('style'))

  return {
    data: new XMLSerializer().serializeToString(svgCopy),
    width,
    height
  }
}

// 下载思维导图
const downloadMindMap = async (format: 'svg' | 'png' | 'jpeg' = 'svg') => {
  const exportSvg = createExportSvg()
  if (!exportSvg) return

  const time = new Date().getTime()
  if (format === 'svg') {
    downloadBlob(new Blob([exportSvg.data], { type: 'image/svg+xml;charset=utf-8' }), `mindmap_${time}.svg`)
    return
  }

  const maxCanvasPixels = 16_000_000
  const scaleFactor = Math.min(3, Math.max(1, Math.sqrt(maxCanvasPixels / (exportSvg.width * exportSvg.height))))
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  canvas.width = Math.ceil(exportSvg.width * scaleFactor)
  canvas.height = Math.ceil(exportSvg.height * scaleFactor)
  ctx.fillStyle = '#ffffff'
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  ctx.scale(scaleFactor, scaleFactor)

  const img = new Image()
  img.onload = () => {
    ctx.drawImage(img, 0, 0)
    const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png'
    canvas.toBlob((blob) => {
      if (!blob) return
      downloadBlob(blob, `mindmap_${time}.${format === 'jpeg' ? 'jpg' : 'png'}`)
    }, mimeType, 0.96)
  }
  img.onerror = () => ElMessage.error('导出图片失败')
  img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(exportSvg.data)
}

// 处理下载命令
const handleDownload = (command: string) => {
  if (command === 'svg' || command === 'png' || command === 'jpeg') {
    downloadMindMap(command)
  }
}

// 重置视图
const resetView = () => {
  mmInstance?.fit()
  scale.value = 1
}

// 放大
const zoomIn = () => {
  if (scale.value < 2) {
    scale.value += 0.1
    applyZoom()
  }
}

// 缩小
const zoomOut = () => {
  if (scale.value > 0.5) {
    scale.value -= 0.1
    applyZoom()
  }
}

// 应用缩放
const applyZoom = () => {
  if (mmInstance && typeof mmInstance.setScale === 'function') {
    mmInstance.setScale(scale.value)
  } else if (mmInstance) {
    console.error('mmInstance does not have setScale method:', mmInstance)
  }
}

// 处理鼠标滚轮缩放
const handleWheel = (event: WheelEvent) => {
  event.preventDefault()
  const delta = event.deltaY > 0 ? -0.1 : 0.1
  if ((scale.value > 0.5 || delta > 0) && (scale.value < 2 || delta < 0)) {
    scale.value += delta
    applyZoom()
  }
}

const handleNodeClick = async (event: MouseEvent) => {
  const textNode = (event.target as Element | null)?.closest?.('text')
  const oldText = textNode?.textContent?.trim()
  if (!oldText || !props.content || oldText === '文档思维导图') return

  try {
    const { value } = await ElMessageBox.prompt('编辑节点文本', '编辑思维导图节点', {
      inputValue: oldText,
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      inputValidator: (value) => Boolean(value.trim()) || '节点文本不能为空'
    })
    const newText = String(value).trim()
    if (newText && newText !== oldText) {
      emit('node-edit', { oldText, newText })
    }
  } catch {
    // 用户取消编辑
  }
}
</script>

<style scoped>
.mindmap-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: #FFFFFF;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
  overflow: hidden;
  min-height: 0;
}

.mindmap-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 16px;
  gap: 12px;
}

.mindmap-subtitle {
  font-size: 12px;
  color: #86909C;
  background-color: #F2F3F5;
  padding: 2px 8px;
  border-radius: 10px;
  margin-right: auto;
}

.action-button {
  border-radius: 6px;
  transition: all 0.3s ease;
  height: 32px;
  padding: 0 12px;
}

.action-button.primary {
  background-color: #165DFF;
  border-color: #165DFF;
  color: #FFFFFF;
}

.action-button.primary:hover {
  background-color: #0E42D2;
  border-color: #0E42D2;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(22, 93, 255, 0.3);
}

.action-button.secondary {
  background-color: #FFFFFF;
  border-color: #C9CDD4;
  color: #4E5969;
}

.action-button.secondary:hover {
  border-color: #165DFF;
  color: #165DFF;
  transform: translateY(-1px);
}

.mindmap-content {
  flex: 1;
  overflow: hidden;
  position: relative;
  background-color: #F9FAFC;
  cursor: grab;
  min-height: 0;
}

.mindmap-content:active {
  cursor: grabbing;
}

.empty-state {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 16px;
}

.mindmap-loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: #4E5969;
  background: rgba(249, 250, 252, 0.82);
  z-index: 2;
}

.loading-icon {
  color: #165DFF;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.empty-icon {
  font-size: 48px;
  color: #C9CDD4;
}

.empty-text {
  font-size: 16px;
  font-weight: 500;
  color: #4E5969;
  margin: 0;
}

.empty-subtext {
  font-size: 14px;
  color: #86909C;
  margin: 0;
}

.markmap-svg {
  width: 100%;
  height: 100%;
  transition: transform 0.2s ease;
}

.markmap-svg :deep(text[data-editable-node="true"]) {
  cursor: text;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .mindmap-header {
    padding: 12px 16px;
  }
  
  .mindmap-title {
    font-size: 14px;
  }
  
  .mindmap-subtitle {
    font-size: 10px;
  }
  
  .action-button {
    padding: 0 8px;
    font-size: 12px;
  }
  
  .mindmap-actions {
    gap: 4px;
  }
}
</style>
