<template>
  <div class="editor-page">
    <!-- 工具栏 -->
    <div class="editor-toolbar">
      <el-button :icon="ArrowLeft" @click="goBack">返回</el-button>
      <el-divider direction="vertical" />
      <div class="title-section">
        <div class="title-input-wrapper" :style="{ width: titleInputWidth + 'px' }">
          <el-input
            v-model="reportTitle"
            class="title-input"
            placeholder="请输入报告标题"
          />
          <span class="title-measure" ref="titleMeasure">{{ reportTitle || '请输入报告标题' }}</span>
        </div>
        <span class="save-status" v-if="saved">✓ 已保存</span>
      </div>
      <div class="toolbar-right">
        <el-button 
          :icon="Refresh" 
          :loading="regenerating"
          @click="handleRegenerateBlocks"
          title="重新生成文档结构"
        >
          重新生成
        </el-button>
        <el-button :icon="Clock">版本</el-button>
        <el-button :icon="Share">分享</el-button>
        <el-divider direction="vertical" />
        <el-button type="primary" :icon="Check" @click="handleSave">保存</el-button>
      </div>
    </div>

    <!-- 主体 -->
    <div class="editor-body">
      <!-- 左侧文件面板 -->
      <div class="left-panel">
        <div class="panel-header">
          <span>📁 来源文件</span>
          <span class="file-count">{{ sourceFiles.length }}个</span>
        </div>
        <div class="panel-body">
          <!-- 上传区 -->
          <el-upload
            class="upload-zone"
            drag
            action="/api/v1/parse/upload"
            :on-success="handleFileUpload"
            :show-file-list="false"
          >
            <div class="upload-content">
              <div class="upload-icon">📄</div>
              <div class="upload-text">拖拽或点击上传</div>
              <div class="upload-hint">支持 PDF / Word / Excel</div>
            </div>
          </el-upload>

          <!-- 来源文件列表 -->
          <div class="file-list">
            <div
              v-for="file in sourceFiles"
              :key="file.id"
              class="file-item"
              :class="{ active: selectedFile?.id === file.id }"
              @click="selectFile(file)"
            >
              <span class="file-icon">{{ getFileIcon(file) }}</span>
              <div class="file-info">
                <div class="file-name">{{ file.alias }}</div>
                <div class="file-meta">
                  <span v-if="file.required" class="required">必需</span>
                  <span v-else>可选</span>
                </div>
              </div>
              <el-button
                size="small"
                :icon="Delete"
                circle
                @click.stop="removeSourceFile(file)"
              />
            </div>
          </div>

          <!-- 添加来源文件定义 -->
          <el-button
            class="add-source-btn"
            :icon="Plus"
            @click="showAddSourceDialog = true"
          >
            添加来源文件定义
          </el-button>
        </div>
      </div>

      <!-- 中间编辑区 -->
      <div class="center-panel">
        <div class="editor-title-bar">
          <div class="view-toggle">
            <el-radio-group v-model="viewMode" size="small">
              <el-radio-button label="edit">📝 编辑</el-radio-button>
              <el-radio-button label="preview">👁 预览</el-radio-button>
            </el-radio-group>
          </div>
          <el-button :icon="Share" circle @click="showGraphModal = true" title="知识图谱" />
        </div>

        <div class="editor-scroll" ref="editorRef">
          <div
            class="editor-content"
            contenteditable="true"
            @mouseup="handleTextSelection"
            v-html="documentContent"
          />
        </div>
      </div>

      <!-- 右侧要素面板 -->
      <div class="right-panel">
        <!-- 要素管理（展示文档中识别的实体） -->
        <div class="element-section">
          <div class="element-header">
            <span class="element-title">
              🏷️ 要素管理
              <span class="element-count">({{ filteredEntities.length }}/{{ entities.length }})</span>
            </span>
            <el-button size="small" :icon="Plus" @click="showAddVariableDialog = true">
              添加
            </el-button>
          </div>
          <!-- 搜索和筛选 -->
          <div class="element-filter" v-if="entities.length > 0">
            <el-input
              v-model="entitySearchKeyword"
              placeholder="搜索要素..."
              size="small"
              :prefix-icon="Search"
              clearable
              class="entity-search"
            />
            <div class="entity-type-filter">
              <el-tag
                v-for="(count, type) in entityTypeCounts"
                :key="type"
                :class="['filter-tag', { active: entityTypeFilter === type }]"
                size="small"
                @click="toggleEntityTypeFilter(type)"
              >
                {{ getEntityTypeIcon(type) }} {{ getEntityTypeName(type) }} ({{ count }})
              </el-tag>
              <el-tag
                v-if="entityTypeFilter"
                class="filter-tag clear"
                size="small"
                @click="entityTypeFilter = ''"
              >
                清除筛选
              </el-tag>
            </div>
          </div>
          <div class="element-body">
            <div class="element-tags-wrap" v-if="filteredEntities.length > 0">
              <div
                v-for="entity in filteredEntities"
                :key="entity.id"
                class="var-tag"
                :class="getEntityTypeClass(entity.type)"
                @click="scrollToEntity(entity.id)"
              >
                <span class="tag-icon">{{ getEntityTypeIcon(entity.type) }}</span>
                <span class="tag-name">{{ entity.text }}</span>
                <span class="tag-status" v-if="entity.confirmed">✓</span>
              </div>
            </div>
            <div class="element-hint" v-if="entities.length === 0">
              选中文本后右键标记为变量
            </div>
            <div class="element-hint" v-else-if="filteredEntities.length === 0">
              没有匹配的要素
            </div>
            <div class="element-hint" v-else>
              点击标签定位到文档位置
            </div>
          </div>
        </div>

        <!-- 按类别分组显示 -->
        <div class="category-section" v-for="(vars, category) in groupedVariables" :key="category">
          <div class="category-header">
            <span
              class="category-dot"
              :style="{ background: getCategoryColor(category) }"
            />
            <span>{{ getCategoryLabel(category) }}</span>
            <span class="category-count">{{ vars.length }}</span>
          </div>
          <div class="category-items">
            <div
              v-for="v in vars"
              :key="v.id"
              class="category-item"
              @click="editVariable(v)"
            >
              <span>{{ v.displayName }}</span>
              <span class="item-value">{{ v.exampleValue || '-' }}</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 右键菜单 -->
    <div
      v-show="contextMenuVisible"
      class="context-menu"
      :style="{ left: contextMenuPos.x + 'px', top: contextMenuPos.y + 'px' }"
    >
      <div class="context-menu-item" @click="markAsVariable('entity')">
        <span class="icon">🏢</span>
        <span>标记为核心实体</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('concept')">
        <span class="icon">💡</span>
        <span>标记为概念/技术</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('data')">
        <span class="icon">📊</span>
        <span>标记为数据/指标</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('location')">
        <span class="icon">📍</span>
        <span>标记为地点/组织</span>
      </div>
      <div class="context-menu-item" @click="markAsVariable('asset')">
        <span class="icon">📑</span>
        <span>标记为资源模板</span>
      </div>
    </div>

    <!-- 添加来源文件对话框 -->
    <el-dialog v-model="showAddSourceDialog" title="添加来源文件定义" width="400">
      <el-form :model="newSourceFile" label-width="80px">
        <el-form-item label="文件别名" required>
          <el-input v-model="newSourceFile.alias" placeholder="如：可研批复" />
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="newSourceFile.description" placeholder="文件描述" />
        </el-form-item>
        <el-form-item label="是否必需">
          <el-switch v-model="newSourceFile.required" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showAddSourceDialog = false">取消</el-button>
        <el-button type="primary" @click="addSourceFile">添加</el-button>
      </template>
    </el-dialog>

    <!-- 添加/编辑变量对话框 -->
    <el-dialog v-model="showVariableDialog" :title="editingVariable ? '编辑变量' : '添加变量'" width="500">
      <el-form :model="variableForm" label-width="100px">
        <el-form-item label="变量名" required>
          <el-input v-model="variableForm.name" placeholder="程序用名，如 project_name" />
        </el-form-item>
        <el-form-item label="显示名称" required>
          <el-input v-model="variableForm.displayName" placeholder="用户可见名称" />
        </el-form-item>
        <el-form-item label="类别">
          <el-select v-model="variableForm.category" style="width: 100%">
            <el-option label="核心实体" value="entity" />
            <el-option label="概念/技术" value="concept" />
            <el-option label="数据/指标" value="data" />
            <el-option label="地点/组织" value="location" />
            <el-option label="资源模板" value="asset" />
          </el-select>
        </el-form-item>
        <el-form-item label="示例值">
          <el-input v-model="variableForm.exampleValue" placeholder="文档中的原始值" />
        </el-form-item>
        <el-form-item label="来源类型">
          <el-select v-model="variableForm.sourceType" style="width: 100%">
            <el-option label="从来源文件提取" value="document" />
            <el-option label="手动输入" value="manual" />
            <el-option label="引用其他变量" value="reference" />
            <el-option label="固定值" value="fixed" />
          </el-select>
        </el-form-item>
        <el-form-item label="来源文件" v-if="variableForm.sourceType === 'document'">
          <el-select v-model="variableForm.sourceFileAlias" style="width: 100%">
            <el-option
              v-for="sf in sourceFiles"
              :key="sf.id"
              :label="sf.alias"
              :value="sf.alias"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="提取方式" v-if="variableForm.sourceType === 'document'">
          <el-select v-model="variableForm.extractType" style="width: 100%">
            <el-option label="直接提取" value="direct" />
            <el-option label="AI 字段提取" value="ai_extract" />
            <el-option label="AI 总结" value="ai_summarize" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showVariableDialog = false">取消</el-button>
        <el-button
          v-if="editingVariable"
          type="danger"
          @click="deleteVariable"
        >
          删除
        </el-button>
        <el-button type="primary" @click="saveVariable">保存</el-button>
      </template>
    </el-dialog>

    <!-- 知识图谱弹窗 -->
    <el-dialog v-model="showGraphModal" title="🔗 知识图谱" width="900">
      <div class="graph-container">
        <div class="graph-legend">
          <div class="legend-title">图例</div>
          <div class="legend-item">
            <span class="legend-dot entity"></span>
            <span>核心实体</span>
          </div>
          <div class="legend-item">
            <span class="legend-dot concept"></span>
            <span>概念/技术</span>
          </div>
          <div class="legend-item">
            <span class="legend-dot data"></span>
            <span>数据/指标</span>
          </div>
          <div class="legend-item">
            <span class="legend-dot location"></span>
            <span>地点/组织</span>
          </div>
        </div>
        <div class="graph-body">
          <div class="graph-placeholder">
            <el-icon size="64" color="#ccc"><Connection /></el-icon>
            <p>知识图谱可视化（开发中）</p>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import {
  ArrowLeft, Clock, Share, Check, Plus, Delete, Connection, Refresh, Search
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { useTemplateStore } from '@/stores/template'
import { documentApi } from '@/api'

const router = useRouter()
const route = useRoute()
const templateStore = useTemplateStore()

const templateId = route.params.templateId
const reportTitle = ref('')
const titleMeasure = ref(null)
const titleInputWidth = ref(120)
const viewMode = ref('edit')
const saved = ref(true)
const editorRef = ref(null)
const loading = ref(false)
const regenerating = ref(false)

// 动态计算标题输入框宽度
watch(reportTitle, () => {
  nextTick(() => {
    if (titleMeasure.value) {
      const measuredWidth = titleMeasure.value.offsetWidth + 30 // 额外边距
      titleInputWidth.value = Math.max(120, Math.min(400, measuredWidth))
    }
  })
})

// 来源文件（从 API 获取）
const sourceFiles = ref([])
const selectedFile = ref(null)
const showAddSourceDialog = ref(false)
const newSourceFile = reactive({
  alias: '',
  description: '',
  required: true
})

// 变量（从 API 获取）
const variables = ref([])

// 文档中的实体（从 blocks 的 elements 中提取）
const entities = ref([])

// 要素搜索和筛选
const entitySearchKeyword = ref('')
const entityTypeFilter = ref('')

// 计算属性：按类型统计要素数量
const entityTypeCounts = computed(() => {
  const counts = {}
  entities.value.forEach(entity => {
    const type = entity.type || 'default'
    counts[type] = (counts[type] || 0) + 1
  })
  return counts
})

// 计算属性：筛选后的要素列表
const filteredEntities = computed(() => {
  let result = entities.value
  
  // 按类型筛选
  if (entityTypeFilter.value) {
    result = result.filter(e => e.type === entityTypeFilter.value)
  }
  
  // 按关键词搜索
  if (entitySearchKeyword.value) {
    const keyword = entitySearchKeyword.value.toLowerCase()
    result = result.filter(e => 
      e.text?.toLowerCase().includes(keyword) ||
      e.type?.toLowerCase().includes(keyword)
    )
  }
  
  return result
})

// 切换类型筛选
function toggleEntityTypeFilter(type) {
  if (entityTypeFilter.value === type) {
    entityTypeFilter.value = ''
  } else {
    entityTypeFilter.value = type
  }
}

// 获取实体类型名称（支持后端返回的英文类型）
function getEntityTypeName(type) {
  const typeNames = {
    // 中文类型
    'entity': '实体',
    'concept': '概念',
    'data': '数据',
    'location': '地点',
    'asset': '资产',
    'person': '人物',
    'org': '组织',
    'date': '日期',
    'product': '产品',
    'event': '事件',
    'law': '法规',
    'default': '其他',
    // 后端返回的英文类型
    'DOC_ID': '文档编号',
    'ORG': '组织机构',
    'PERSON': '人物',
    'LOCATION': '地点',
    'LOC': '地点',
    'DATE': '日期',
    'TIME': '时间',
    'MONEY': '金额',
    'PERCENT': '百分比',
    'PRODUCT': '产品',
    'EVENT': '事件',
    'LAW': '法规',
    'WORK_OF_ART': '作品',
    'LANGUAGE': '语言',
    'NORP': '民族/宗教/政治团体',
    'FAC': '设施',
    'GPE': '地理政治实体',
    'CARDINAL': '数量',
    'ORDINAL': '序数',
    'QUANTITY': '数量单位',
    'TITLE': '职务/头衔',
    'STANDARD': '标准规范',
    'RATING': '评级',
    'PERIOD': '时间段',
    'SCORE': '评分',
    'LEVEL': '等级'
  }
  return typeNames[type] || typeNames[type?.toUpperCase()] || type || '其他'
}

/**
 * 从结构化文档的 blocks 中提取所有实体
 */
function extractEntitiesFromBlocks(blocks) {
  const entityList = []
  const entityMap = new Map() // 用于去重
  
  if (!blocks || !Array.isArray(blocks)) {
    return entityList
  }
  
  for (const block of blocks) {
    if (!block.elements || !Array.isArray(block.elements)) {
      continue
    }
    
    for (const element of block.elements) {
      if (element.type === 'entity' && element.entityId) {
        // 使用 entityId 去重
        if (!entityMap.has(element.entityId)) {
          entityMap.set(element.entityId, true)
          entityList.push({
            id: element.entityId,
            text: element.entityText || '',
            type: element.entityType || 'ENTITY',
            confirmed: element.confirmed || false
          })
        }
      }
    }
  }
  
  return entityList
}

// 加载模板数据
onMounted(async () => {
  await fetchTemplateData()
})

async function fetchTemplateData() {
  loading.value = true
  try {
    await templateStore.fetchTemplateDetail(templateId)
    
    // 设置模板标题
    reportTitle.value = templateStore.currentTemplate?.name || '未命名模板'
    
    // 设置来源文件
    sourceFiles.value = templateStore.sourceFiles || []
    
    // 设置变量
    variables.value = templateStore.variables || []
    
    // 根据 baseDocumentId 获取文档结构化内容
    const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
    if (baseDocumentId) {
      try {
        const structuredDoc = await documentApi.getStructured(baseDocumentId)
        // 将结构化文档的 blocks 和 images 合并渲染
        if (structuredDoc && structuredDoc.blocks && structuredDoc.blocks.length > 0) {
          documentContent.value = renderStructuredDocument(structuredDoc)
          // 提取文档中的实体
          entities.value = extractEntitiesFromBlocks(structuredDoc.blocks)
        } else {
          documentContent.value = emptyPlaceholder
          entities.value = []
        }
      } catch (docError) {
        console.warn('获取文档内容失败:', docError)
        documentContent.value = emptyPlaceholder
        entities.value = []
      }
    } else {
      documentContent.value = emptyPlaceholder
      entities.value = []
    }
  } catch (error) {
    console.error('加载模板失败:', error)
    ElMessage.error('加载模板失败')
  } finally {
    loading.value = false
  }
}
const showVariableDialog = ref(false)
const showAddVariableDialog = ref(false)
const editingVariable = ref(null)
const variableForm = reactive({
  name: '',
  displayName: '',
  category: 'entity',
  exampleValue: '',
  sourceType: 'document',
  sourceFileAlias: '',
  extractType: 'direct'
})

// 右键菜单
const contextMenuVisible = ref(false)
const contextMenuPos = reactive({ x: 0, y: 0 })
const selectedText = ref('')
const selectionRange = ref(null)

// 知识图谱
const showGraphModal = ref(false)

// 文档内容（从 API 获取或空白）
const documentContent = ref('')

// 空白模板时的占位提示
const emptyPlaceholder = `
  <div class="empty-editor-placeholder">
    <h2>📝 开始编辑您的模板</h2>
    <p>这是一个空白模板。您可以：</p>
    <ul>
      <li>在左侧添加来源文件定义</li>
      <li>在右侧面板添加变量</li>
      <li>直接在此处编辑模板内容</li>
      <li>选中文本后右键将其标记为变量</li>
    </ul>
  </div>
`

/**
 * 渲染结构化文档（合并 blocks 和 images）
 * 根据 index 排序，将图片插入到正确的位置
 */
function renderStructuredDocument(structuredDoc) {
  const blocks = structuredDoc.blocks || []
  const images = structuredDoc.images || []
  const tables = structuredDoc.tables || []
  const paragraphs = structuredDoc.paragraphs || []
  
  // 将所有元素合并
  const allElements = []
  
  // 从 blocks 中提取实体映射（按文本内容匹配）
  const entityMap = buildEntityMap(blocks)
  
  // 检查 paragraphs 是否有 runs（带格式信息）
  const hasParagraphsWithRuns = paragraphs.some(p => p.runs && p.runs.length > 0)
  
  if (hasParagraphsWithRuns) {
    // 使用 paragraphs 渲染（保留格式 + 合并实体高亮）
    paragraphs.forEach(para => {
      allElements.push({
        type: 'paragraph',
        index: para.index,
        html: renderParagraphWithRunsAndEntities(para, entityMap)
      })
    })
  } else if (blocks.length > 0) {
    // 回退到 blocks 渲染（带实体标记，但无格式）
    blocks.forEach(block => {
      if (block.type === 'page') return // 跳过根节点
      allElements.push({
        type: 'block',
        index: block.index,
        html: block.markedHtml || block.html || block.plainText || ''
      })
    })
  }
  
  // 添加图片（保持原始尺寸，不显示说明文字）
  images.forEach(img => {
    // 图片样式：保持原始尺寸，不强制居中
    const imgStyle = img.width && img.height 
      ? `width:${img.width}px; height:${img.height}px;`
      : 'max-width: 100%; height: auto;'
    
    allElements.push({
      type: 'image',
      index: img.index,
      html: `<div class="doc-image" style="margin: 8px 0;">
        <img src="${img.url}" alt="${img.alt || '图片'}" style="${imgStyle}" />
      </div>`
    })
  })
  
  // 添加表格
  tables.forEach(table => {
    allElements.push({
      type: 'table',
      index: table.index,
      html: renderTable(table, entityMap)
    })
  })
  
  // 按 index 排序
  allElements.sort((a, b) => (a.index || 0) - (b.index || 0))
  
  // 合并 HTML
  return allElements.map(el => el.html).join('')
}

/**
 * 渲染表格
 */
function renderTable(table, entityMap) {
  if (!table.rows || table.rows.length === 0) {
    return '<div class="doc-table-empty">空表格</div>'
  }
  
  let html = '<div class="doc-table-container"><table class="doc-table">'
  
  table.rows.forEach((row, rowIndex) => {
    html += '<tr>'
    row.forEach((cell, colIndex) => {
      const tag = rowIndex === 0 ? 'th' : 'td'
      const attrs = []
      
      if (cell.rowSpan && cell.rowSpan > 1) {
        attrs.push(`rowspan="${cell.rowSpan}"`)
      }
      if (cell.colSpan && cell.colSpan > 1) {
        attrs.push(`colspan="${cell.colSpan}"`)
      }
      
      // 单元格样式
      const styleAttrs = []
      if (cell.style) {
        if (cell.style.alignment) {
          const alignMap = { 'left': 'left', 'center': 'center', 'right': 'right', 'both': 'justify' }
          styleAttrs.push(`text-align:${alignMap[cell.style.alignment] || cell.style.alignment}`)
        }
        if (cell.style.backgroundColor) {
          styleAttrs.push(`background-color:#${cell.style.backgroundColor}`)
        }
      }
      if (styleAttrs.length > 0) {
        attrs.push(`style="${styleAttrs.join(';')}"`)
      }
      
      // 单元格内容（支持 runs 格式）
      let content = ''
      if (cell.runs && cell.runs.length > 0) {
        content = cell.runs.map(run => renderTextRunWithEntities(run, entityMap)).join('')
      } else {
        content = highlightEntitiesInText(cell.text || '', entityMap)
      }
      
      html += `<${tag} ${attrs.join(' ')}>${content}</${tag}>`
    })
    html += '</tr>'
  })
  
  html += '</table></div>'
  return html
}

/**
 * 从 blocks 中构建实体映射
 * 返回 { entityText: { entityId, entityType, confirmed } }
 */
function buildEntityMap(blocks) {
  const entityMap = new Map()
  
  blocks.forEach(block => {
    if (!block.elements) return
    
    block.elements.forEach(el => {
      if (el.type === 'entity' && el.entityText) {
        // 使用实体文本作为 key（可能有多个相同文本的实体）
        if (!entityMap.has(el.entityText)) {
          entityMap.set(el.entityText, [])
        }
        entityMap.get(el.entityText).push({
          entityId: el.entityId,
          entityType: el.entityType,
          confirmed: el.confirmed
        })
      }
    })
  })
  
  return entityMap
}

/**
 * 渲染带格式和实体高亮的段落
 */
function renderParagraphWithRunsAndEntities(para, entityMap) {
  if (!para.runs || para.runs.length === 0) {
    // 没有 runs，使用纯文本
    const content = highlightEntitiesInText(para.content || '', entityMap)
    return wrapWithParagraphTag(content, para.type, para.style)
  }
  
  // 渲染每个 run，同时应用实体高亮
  const runsHtml = para.runs.map(run => renderTextRunWithEntities(run, entityMap)).join('')
  return wrapWithParagraphTag(runsHtml, para.type, para.style)
}

/**
 * 渲染带格式的段落（使用 runs）- 保留兼容
 */
function renderParagraphWithRuns(para) {
  if (!para.runs || para.runs.length === 0) {
    const content = escapeHtml(para.content || '').replace(/\n/g, '<br>')
    return wrapWithParagraphTag(content, para.type, para.style)
  }
  
  const runsHtml = para.runs.map(run => renderTextRun(run)).join('')
  return wrapWithParagraphTag(runsHtml, para.type, para.style)
}

/**
 * 渲染单个文本片段（Run）并高亮实体
 */
function renderTextRunWithEntities(run, entityMap) {
  if (!run || !run.text) return ''
  
  // 先在文本中查找并高亮实体
  const highlightedText = highlightEntitiesInText(run.text, entityMap)
  
  // 如果文本被实体高亮处理过（包含 span 标签），需要特殊处理样式
  const hasEntityHighlight = highlightedText.includes('entity-highlight')
  
  // 构建样式
  const styles = buildRunStyles(run)
  
  // 如果没有样式，直接返回高亮后的文本
  if (styles.length === 0) {
    return highlightedText.replace(/\n/g, '<br>')
  }
  
  // 如果有实体高亮，需要用 span 包裹整体样式
  if (hasEntityHighlight) {
    return `<span style="${styles.join(';')}">${highlightedText.replace(/\n/g, '<br>')}</span>`
  }
  
  // 普通文本，处理换行并应用样式
  const text = escapeHtml(run.text).replace(/\n/g, '<br>')
  
  // 上下标特殊处理
  if (run.verticalAlign === 'superscript') {
    return `<sup style="${styles.join(';')}">${text}</sup>`
  } else if (run.verticalAlign === 'subscript') {
    return `<sub style="${styles.join(';')}">${text}</sub>`
  }
  
  return `<span style="${styles.join(';')}">${text}</span>`
}

/**
 * 在文本中查找并高亮实体
 */
function highlightEntitiesInText(text, entityMap) {
  if (!text || !entityMap || entityMap.size === 0) {
    return escapeHtml(text || '')
  }
  
  // 按实体文本长度降序排序（优先匹配长的）
  const sortedEntities = Array.from(entityMap.keys()).sort((a, b) => b.length - a.length)
  
  let result = text
  const replacements = []
  
  // 找出所有需要替换的位置
  for (const entityText of sortedEntities) {
    const entities = entityMap.get(entityText)
    if (!entities || entities.length === 0) continue
    
    let searchStart = 0
    let entityIndex = 0
    
    while (true) {
      const pos = result.indexOf(entityText, searchStart)
      if (pos === -1) break
      
      // 获取对应的实体信息（循环使用）
      const entity = entities[entityIndex % entities.length]
      
      replacements.push({
        start: pos,
        end: pos + entityText.length,
        text: entityText,
        entity: entity
      })
      
      searchStart = pos + entityText.length
      entityIndex++
    }
  }
  
  // 按位置排序，从后往前替换（避免位置偏移）
  replacements.sort((a, b) => b.start - a.start)
  
  // 检查重叠，移除被包含的替换
  const finalReplacements = []
  for (const rep of replacements) {
    const hasOverlap = finalReplacements.some(
      existing => rep.start < existing.end && rep.end > existing.start
    )
    if (!hasOverlap) {
      finalReplacements.push(rep)
    }
  }
  
  // 执行替换
  for (const rep of finalReplacements) {
    const before = result.substring(0, rep.start)
    const after = result.substring(rep.end)
    const highlighted = renderEntityHighlight(rep.text, rep.entity)
    result = before + highlighted + after
  }
  
  // 对非实体部分进行 HTML 转义
  // 由于实体部分已经包含 HTML，需要分段处理
  return escapeNonEntityText(result)
}

/**
 * 转义非实体部分的文本
 */
function escapeNonEntityText(text) {
  // 分割出实体标签和普通文本
  const parts = text.split(/(<span class="entity-highlight[^>]*>.*?<\/span>)/g)
  
  return parts.map(part => {
    if (part.startsWith('<span class="entity-highlight')) {
      return part // 保留实体标签
    }
    return escapeHtml(part) // 转义普通文本
  }).join('')
}

/**
 * 渲染实体高亮标签
 */
function renderEntityHighlight(text, entity) {
  const cssClass = getEntityCssClass(entity.entityType)
  const confirmedMark = entity.confirmed ? ' ✓' : ''
  
  return `<span class="${cssClass}" ` +
    `data-entity-id="${entity.entityId || ''}" ` +
    `data-type="${entity.entityType || ''}" ` +
    `onclick="showEntityEditModal(event,'${entity.entityId || ''}')" ` +
    `contenteditable="false">${escapeHtml(text)}${confirmedMark}</span>`
}

/**
 * 获取实体类型对应的 CSS 类
 */
function getEntityCssClass(entityType) {
  const typeMap = {
    'PERSON': 'entity-highlight person',
    'ORG': 'entity-highlight org',
    'ORGANIZATION': 'entity-highlight org',
    'LOC': 'entity-highlight location',
    'LOCATION': 'entity-highlight location',
    'GPE': 'entity-highlight location',
    'DATE': 'entity-highlight date',
    'TIME': 'entity-highlight date',
    'MONEY': 'entity-highlight data',
    'NUMBER': 'entity-highlight data',
    'PERCENT': 'entity-highlight data',
    'DATA': 'entity-highlight data',
    'CONCEPT': 'entity-highlight concept',
    'PRODUCT': 'entity-highlight product',
    'EVENT': 'entity-highlight event'
  }
  return typeMap[entityType?.toUpperCase()] || 'entity-highlight entity'
}

/**
 * 构建 Run 的 CSS 样式数组
 */
function buildRunStyles(run) {
  const styles = []
  
  if (run.fontFamily) {
    styles.push(`font-family:${run.fontFamily}`)
  }
  if (run.fontSize && run.fontSize > 0) {
    styles.push(`font-size:${run.fontSize}pt`)
  }
  if (run.color) {
    const color = run.color.startsWith('#') ? run.color : `#${run.color}`
    styles.push(`color:${color}`)
  }
  if (run.highlightColor) {
    const bgColor = getHighlightColor(run.highlightColor)
    styles.push(`background-color:${bgColor}`)
  }
  if (run.bold) {
    styles.push('font-weight:bold')
  }
  if (run.italic) {
    styles.push('font-style:italic')
  }
  
  const textDecorations = []
  if (run.underline && run.underline !== 'none') {
    const underlineStyle = run.underline === 'double' ? 'double' : 
                           run.underline === 'wave' || run.underline === 'wavy' ? 'wavy' :
                           run.underline === 'dotted' ? 'dotted' :
                           run.underline === 'dashed' ? 'dashed' : 'solid'
    textDecorations.push(`underline ${underlineStyle}`)
  }
  if (run.strikeThrough) {
    textDecorations.push('line-through')
  }
  if (textDecorations.length > 0) {
    styles.push(`text-decoration:${textDecorations.join(' ')}`)
  }
  
  return styles
}

/**
 * 渲染单个文本片段（Run）- 保留兼容
 */
function renderTextRun(run) {
  if (!run || !run.text) return ''
  
  // 转义 HTML 并将换行符转换为 <br>
  let text = escapeHtml(run.text).replace(/\n/g, '<br>')
  const styles = buildRunStyles(run)
  
  // 上下标
  if (run.verticalAlign === 'superscript') {
    return styles.length > 0 ? `<sup style="${styles.join(';')}">${text}</sup>` : `<sup>${text}</sup>`
  } else if (run.verticalAlign === 'subscript') {
    return styles.length > 0 ? `<sub style="${styles.join(';')}">${text}</sub>` : `<sub>${text}</sub>`
  }
  
  // 如果没有样式，直接返回文本
  if (styles.length === 0) {
    return text
  }
  
  return `<span style="${styles.join(';')}">${text}</span>`
}

/**
 * 获取高亮颜色对应的 CSS 颜色
 */
function getHighlightColor(colorName) {
  const colors = {
    'yellow': '#ffff00',
    'green': '#00ff00',
    'cyan': '#00ffff',
    'magenta': '#ff00ff',
    'blue': '#0000ff',
    'red': '#ff0000',
    'darkblue': '#000080',
    'darkcyan': '#008080',
    'darkgreen': '#008000',
    'darkmagenta': '#800080',
    'darkred': '#800000',
    'darkyellow': '#808000',
    'darkgray': '#808080',
    'lightgray': '#c0c0c0',
    'black': '#000000'
  }
  return colors[colorName.toLowerCase()] || colorName
}

/**
 * 用段落标签包裹内容
 */
function wrapWithParagraphTag(content, type, style) {
  // 段落样式
  const styleAttrs = []
  if (style) {
    // 对齐方式
    if (style.alignment) {
      const alignMap = {
        'left': 'left',
        'center': 'center',
        'right': 'right',
        'both': 'justify',  // 两端对齐
        'justify': 'justify'
      }
      styleAttrs.push(`text-align:${alignMap[style.alignment] || style.alignment}`)
    }
    
    // 左缩进（twips -> pt，1 twip = 1/20 pt）
    if (style.indentLeft) {
      styleAttrs.push(`padding-left:${style.indentLeft / 20}pt`)
    }
    
    // 右缩进
    if (style.indentRight) {
      styleAttrs.push(`padding-right:${style.indentRight / 20}pt`)
    }
    
    // 首行缩进
    if (style.indentFirstLine) {
      styleAttrs.push(`text-indent:${style.indentFirstLine / 20}pt`)
    }
    
    // 悬挂缩进（负的首行缩进 + 增加左边距）
    if (style.indentHanging) {
      const hangingPt = style.indentHanging / 20
      styleAttrs.push(`text-indent:-${hangingPt}pt`)
      // 如果没有左缩进，需要增加左边距来补偿
      if (!style.indentLeft) {
        styleAttrs.push(`margin-left:${hangingPt}pt`)
      }
    }
    
    // 段前间距
    if (style.spacingBefore) {
      styleAttrs.push(`margin-top:${style.spacingBefore / 20}pt`)
    }
    
    // 段后间距
    if (style.spacingAfter) {
      styleAttrs.push(`margin-bottom:${style.spacingAfter / 20}pt`)
    }
    
    // 行距处理
    if (style.lineSpacing) {
      // getSpacingBetween 返回的是倍数（如 1.0, 1.5, 2.0）
      if (style.lineSpacing >= 1 && style.lineSpacing <= 5) {
        styleAttrs.push(`line-height:${style.lineSpacing}`)
      }
    } else if (style.lineSpacingValue && style.lineSpacingRule) {
      // 精确行距值处理
      const rule = style.lineSpacingRule.toLowerCase()
      if (rule === 'exact') {
        // 固定行距（twips -> pt）
        styleAttrs.push(`line-height:${style.lineSpacingValue / 20}pt`)
      } else if (rule === 'atleast' || rule === 'at_least') {
        // 最小行距
        styleAttrs.push(`min-height:${style.lineSpacingValue / 20}pt`)
      } else if (rule === 'auto') {
        // 倍数行距（240 twips = 1 倍行距）
        styleAttrs.push(`line-height:${style.lineSpacingValue / 240}`)
      }
    }
    
    // 字体信息（段落级别的默认字体）
    if (style.fontFamily) {
      styleAttrs.push(`font-family:${style.fontFamily}`)
    }
    if (style.fontSize) {
      styleAttrs.push(`font-size:${style.fontSize}pt`)
    }
  }
  
  const styleAttr = styleAttrs.length > 0 ? ` style="${styleAttrs.join(';')}"` : ''
  
  // 目录项特殊处理
  if (type === 'toc_item') {
    const pageNum = style?.tocPageNum || ''
    // 计算缩进级别（根据章节号判断）
    let level = 0
    const levelMatch = content.match(/^(\d+(?:\.\d+)*)/)
    if (levelMatch) {
      level = (levelMatch[1].match(/\./g) || []).length
    }
    const indentStyle = level > 0 ? ` style="padding-left:${level * 20}px"` : ''
    return `<div class="doc-toc-item"${indentStyle}><span class="toc-title">${content}</span><span class="toc-dots"></span><span class="toc-page">${pageNum}</span></div>`
  }
  
  switch (type) {
    case 'heading1':
      return `<h1${styleAttr}>${content}</h1>`
    case 'heading2':
      return `<h2${styleAttr}>${content}</h2>`
    case 'heading3':
      return `<h3${styleAttr}>${content}</h3>`
    case 'heading':
      return `<h2${styleAttr}>${content}</h2>`
    case 'toc':
      return `<div class="doc-toc-title"${styleAttr}>${content}</div>`
    case 'bullet':
    case 'list_item':
      return `<div class="doc-list-item bullet"${styleAttr}>${content}</div>`
    case 'ordered':
      return `<div class="doc-list-item ordered"${styleAttr}>${content}</div>`
    case 'quote':
      return `<blockquote${styleAttr}>${content}</blockquote>`
    case 'code':
      return `<pre><code>${content}</code></pre>`
    case 'title':
      return `<h1 class="doc-title"${styleAttr}>${content}</h1>`
    default:
      return `<p${styleAttr}>${content}</p>`
  }
}

/**
 * HTML 转义
 */
function escapeHtml(text) {
  if (!text) return ''
  return text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
}

// 计算属性
const groupedVariables = computed(() => {
  const groups = {}
  variables.value.forEach(v => {
    const cat = v.category || 'other'
    if (!groups[cat]) groups[cat] = []
    groups[cat].push(v)
  })
  return groups
})

// 方法
function goBack() {
  router.back()
}

function handleSave() {
  saved.value = true
  ElMessage.success('保存成功')
}

// 重新生成文档块结构
async function handleRegenerateBlocks() {
  const baseDocumentId = templateStore.currentTemplate?.baseDocumentId
  if (!baseDocumentId) {
    ElMessage.warning('没有关联的示例文档')
    return
  }

  regenerating.value = true
  try {
    const result = await documentApi.regenerateBlocks(baseDocumentId)
    ElMessage.success(`重新生成成功: ${result.blockCount} 个文档块, ${result.entityCount} 个实体`)
    
    // 重新加载文档内容
    const structuredDoc = await documentApi.getStructured(baseDocumentId)
    if (structuredDoc && structuredDoc.blocks && structuredDoc.blocks.length > 0) {
      documentContent.value = renderStructuredDocument(structuredDoc)
      // 重新提取实体
      entities.value = extractEntitiesFromBlocks(structuredDoc.blocks)
    }
  } catch (error) {
    console.error('重新生成失败:', error)
    ElMessage.error('重新生成失败: ' + (error.message || '未知错误'))
  } finally {
    regenerating.value = false
  }
}

function getFileIcon(file) {
  return '📄'
}

function selectFile(file) {
  selectedFile.value = file
}

async function removeSourceFile(file) {
  try {
    await templateStore.deleteSourceFile(file.id)
    sourceFiles.value = sourceFiles.value.filter(f => f.id !== file.id)
    ElMessage.success('删除成功')
  } catch (error) {
    ElMessage.error('删除失败: ' + error.message)
  }
}

async function addSourceFile() {
  if (!newSourceFile.alias) {
    ElMessage.warning('请输入文件别名')
    return
  }
  try {
    const sf = await templateStore.addSourceFile(templateId, newSourceFile)
    sourceFiles.value.push(sf)
    showAddSourceDialog.value = false
    Object.assign(newSourceFile, { alias: '', description: '', required: true })
    ElMessage.success('添加成功')
  } catch (error) {
    ElMessage.error('添加失败: ' + error.message)
  }
}

function getCategoryIcon(category) {
  const icons = {
    entity: '🏢',
    concept: '💡',
    data: '📊',
    location: '📍',
    asset: '📑'
  }
  return icons[category] || '📌'
}

function getCategoryColor(category) {
  const colors = {
    entity: '#1890ff',
    concept: '#722ed1',
    data: '#52c41a',
    location: '#faad14',
    asset: '#eb2f96'
  }
  return colors[category] || '#8c8c8c'
}

function getCategoryLabel(category) {
  const labels = {
    entity: '核心实体',
    concept: '概念/技术',
    data: '数据/指标',
    location: '地点/组织',
    asset: '资源模板'
  }
  return labels[category] || '其他'
}

/**
 * 根据实体类型获取图标
 */
function getEntityTypeIcon(type) {
  const icons = {
    'PERSON': '👤',
    'ORGANIZATION': '🏢',
    'ORG': '🏢',
    'LOCATION': '📍',
    'LOC': '📍',
    'DATE': '📅',
    'TIME': '⏰',
    'PERIOD': '📆',
    'MONEY': '💰',
    'PERCENT': '📊',
    'PRODUCT': '📦',
    'EVENT': '📋',
    'FACILITY': '🏭',
    'FAC': '🏭',
    'GPE': '🌍',
    'LAW': '⚖️',
    'WORK_OF_ART': '🎨',
    'LANGUAGE': '🗣️',
    'QUANTITY': '🔢',
    'ORDINAL': '🔢',
    'CARDINAL': '🔢',
    'ENTITY': '🏷️',
    'DOC_ID': '📄',
    'NORP': '👥',
    'TITLE': '🎖️',
    'STANDARD': '📋',
    'RATING': '⭐',
    'SCORE': '💯',
    'LEVEL': '📊'
  }
  return icons[type?.toUpperCase()] || '🏷️'
}

/**
 * 根据实体类型获取样式类名
 */
function getEntityTypeClass(type) {
  const typeMap = {
    'PERSON': 'entity-person',
    'ORGANIZATION': 'entity-org',
    'LOCATION': 'entity-location',
    'DATE': 'entity-date',
    'TIME': 'entity-date',
    'MONEY': 'entity-data',
    'PERCENT': 'entity-data',
    'PRODUCT': 'entity-product',
    'EVENT': 'entity-event',
    'FACILITY': 'entity-org',
    'GPE': 'entity-location',
    'LAW': 'entity-law'
  }
  return typeMap[type?.toUpperCase()] || 'entity-default'
}

/**
 * 滚动到文档中的指定实体
 */
function scrollToEntity(entityId) {
  const editorEl = document.querySelector('.editor-content')
  if (!editorEl) return
  
  const entitySpan = editorEl.querySelector(`[data-entity-id="${entityId}"]`)
  if (entitySpan) {
    entitySpan.scrollIntoView({ behavior: 'smooth', block: 'center' })
    // 添加高亮闪烁效果
    entitySpan.classList.add('entity-highlight-flash')
    setTimeout(() => {
      entitySpan.classList.remove('entity-highlight-flash')
    }, 2000)
  }
}

function editVariable(variable) {
  editingVariable.value = variable
  Object.assign(variableForm, variable)
  showVariableDialog.value = true
}

async function saveVariable() {
  if (!variableForm.name || !variableForm.displayName) {
    ElMessage.warning('请填写必要字段')
    return
  }

  try {
    if (editingVariable.value) {
      // 更新
      const updated = await templateStore.updateVariable(editingVariable.value.id, variableForm)
      Object.assign(editingVariable.value, updated)
      ElMessage.success('更新成功')
    } else {
      // 新增
      const newVar = await templateStore.addVariable(templateId, variableForm)
      variables.value.push(newVar)
      ElMessage.success('添加成功')
    }

    showVariableDialog.value = false
    resetVariableForm()
  } catch (error) {
    ElMessage.error('保存失败: ' + error.message)
  }
}

async function deleteVariable() {
  if (editingVariable.value) {
    try {
      await templateStore.deleteVariable(editingVariable.value.id)
      variables.value = variables.value.filter(v => v.id !== editingVariable.value.id)
      showVariableDialog.value = false
      resetVariableForm()
      ElMessage.success('删除成功')
    } catch (error) {
      ElMessage.error('删除失败: ' + error.message)
    }
  }
}

function resetVariableForm() {
  editingVariable.value = null
  Object.assign(variableForm, {
    name: '',
    displayName: '',
    category: 'entity',
    exampleValue: '',
    sourceType: 'document',
    sourceFileAlias: '',
    extractType: 'direct'
  })
}

function handleTextSelection(event) {
  const selection = window.getSelection()
  const text = selection.toString().trim()

  if (text) {
    selectedText.value = text
    selectionRange.value = selection.getRangeAt(0)
    contextMenuPos.x = event.clientX
    contextMenuPos.y = event.clientY
    contextMenuVisible.value = true
  } else {
    contextMenuVisible.value = false
  }
}

function markAsVariable(category) {
  if (!selectedText.value) return

  // 生成变量名
  const varName = 'var_' + Date.now()

  // 添加变量
  variables.value.push({
    id: Date.now().toString(),
    name: varName,
    displayName: selectedText.value.slice(0, 20),
    category,
    exampleValue: selectedText.value,
    sourceType: 'document'
  })

  // 关闭菜单
  contextMenuVisible.value = false
  selectedText.value = ''

  ElMessage.success('变量标记成功')
}

function handleFileUpload(response) {
  if (response.code === 200) {
    ElMessage.success('文件上传成功')
  }
}

// 点击其他地方关闭右键菜单
function handleClickOutside(event) {
  if (!event.target.closest('.context-menu')) {
    contextMenuVisible.value = false
  }
}

onMounted(() => {
  document.addEventListener('click', handleClickOutside)
})

onUnmounted(() => {
  document.removeEventListener('click', handleClickOutside)
})
</script>

<style lang="scss" scoped>
.editor-page {
  height: calc(100vh - 56px);
  display: flex;
  flex-direction: column;
  background: var(--bg);
}

.editor-toolbar {
  height: 56px;
  background: #fff;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 16px;
  gap: 12px;
  flex-shrink: 0;
  
  .title-section {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    min-width: 0;
  }

  .title-input-wrapper {
    position: relative;
    display: inline-block;
    min-width: 150px;
    max-width: 500px;
    
    .title-input {
      width: 100%;

      :deep(.el-input__wrapper) {
        box-shadow: none;
        background: transparent;
        border-radius: 6px;

        &:hover, &.is-focus {
          background: var(--bg);
        }
      }
      
      :deep(.el-input__inner) {
        font-size: 16px;
        font-weight: 600;
      }
    }
    
    .title-measure {
      position: absolute;
      visibility: hidden;
      white-space: nowrap;
      font-size: 16px;
      font-weight: 600;
      padding: 0 11px;
      pointer-events: none;
    }
  }

  .save-status {
    color: var(--success);
    font-size: 12px;
    white-space: nowrap;
    opacity: 0.8;
  }

  .toolbar-right {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-shrink: 0;
  }
}

.editor-body {
  flex: 1;
  display: flex;
  overflow: hidden;
}

.left-panel {
  width: 260px;
  background: #fff;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;

  .panel-header {
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 600;
    display: flex;
    justify-content: space-between;

    .file-count {
      color: var(--text-3);
      font-weight: normal;
    }
  }

  .panel-body {
    flex: 1;
    overflow-y: auto;
    padding: 12px;
  }
}

.upload-zone {
  border: 2px dashed var(--border);
  border-radius: 10px;
  margin-bottom: 16px;

  :deep(.el-upload-dragger) {
    padding: 20px;
    border: none;
    background: transparent;
  }

  .upload-content {
    text-align: center;
  }

  .upload-icon {
    font-size: 32px;
    margin-bottom: 8px;
  }

  .upload-text {
    font-size: 13px;
    color: var(--text-2);
  }

  .upload-hint {
    font-size: 11px;
    color: var(--text-3);
  }
}

.file-list {
  margin-bottom: 16px;
}

.file-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: all 0.2s;

  &:hover, &.active {
    border-color: var(--primary);
    background: var(--primary-light);
  }

  .file-icon {
    font-size: 24px;
  }

  .file-info {
    flex: 1;
    min-width: 0;

    .file-name {
      font-size: 12px;
      font-weight: 500;
    }

    .file-meta {
      font-size: 11px;
      color: var(--text-3);

      .required {
        color: var(--danger);
      }
    }
  }
}

.add-source-btn {
  width: 100%;
}

.center-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #fff;
  overflow: hidden;

  .editor-title-bar {
    padding: 12px 24px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: var(--bg);
  }

  .editor-scroll {
    flex: 1;
    overflow-y: auto;
    padding: 24px 32px;
  }

  .editor-content {
    max-width: 800px;
    margin: 0 auto;
    outline: none;

    :deep(h1) {
      font-size: 24px;
      font-weight: 700;
      margin-bottom: 24px;
    }

    :deep(h2) {
      font-size: 18px;
      font-weight: 600;
      margin: 28px 0 16px;
    }

    :deep(p) {
      margin-bottom: 12px;
      line-height: 1.6;
    }

    :deep(ul) {
      margin-bottom: 16px;
      padding-left: 24px;

      li {
        margin-bottom: 8px;
      }
    }
    
    // 目录样式
    :deep(.doc-toc-title) {
      font-size: 18pt;
      font-weight: bold;
      text-align: center;
      margin: 20px 0 16px;
    }
    
    :deep(.doc-toc-item) {
      display: flex;
      align-items: baseline;
      padding: 6px 0;
      line-height: 1.6;
      cursor: pointer;
      transition: background-color 0.2s;
      
      &:hover {
        background-color: #f5f5f5;
      }
      
      .toc-title {
        flex-shrink: 0;
        white-space: nowrap;
      }
      
      .toc-dots {
        flex: 1;
        border-bottom: 1px dotted #999;
        margin: 0 8px;
        min-width: 20px;
        height: 0.6em;
      }
      
      .toc-page {
        flex-shrink: 0;
        color: #666;
        min-width: 20px;
        text-align: right;
      }
    }
    
    // 表格样式
    :deep(.doc-table-container) {
      margin: 16px 0;
      overflow-x: auto;
    }
    
    :deep(.doc-table) {
      width: 100%;
      border-collapse: collapse;
      font-size: 14px;
      
      th, td {
        border: 1px solid #ddd;
        padding: 8px 12px;
        text-align: left;
        vertical-align: top;
        line-height: 1.5;
      }
      
      th {
        background-color: #f5f5f5;
        font-weight: bold;
      }
      
      tr:nth-child(even) td {
        background-color: #fafafa;
      }
      
      tr:hover td {
        background-color: #f0f7ff;
      }
    }
    
    :deep(.doc-table-empty) {
      padding: 20px;
      text-align: center;
      color: #999;
      border: 1px dashed #ddd;
      margin: 16px 0;
    }
    
    // 列表项样式
    :deep(.doc-list-item) {
      position: relative;
      margin-bottom: 8px;
      line-height: 1.6;
      
      &.bullet {
        padding-left: 1.5em;
        &::before {
          content: '•';
          position: absolute;
          left: 0;
        }
      }
      
      &.ordered {
        padding-left: 2em;
        counter-increment: doc-list;
        &::before {
          content: counter(doc-list) '.';
          position: absolute;
          left: 0;
        }
      }
    }
    
    // 重置列表计数器
    :deep(p + .doc-list-item.ordered:first-of-type),
    :deep(.doc-list-item.bullet + .doc-list-item.ordered) {
      counter-reset: doc-list;
    }
    
    // 块引用样式
    :deep(blockquote) {
      margin: 16px 0;
      padding: 12px 20px;
      border-left: 4px solid #ddd;
      background: #f9f9f9;
      color: #666;
    }
    
    // 代码块样式
    :deep(pre) {
      margin: 16px 0;
      padding: 16px;
      background: #f5f5f5;
      border-radius: 4px;
      overflow-x: auto;
      
      code {
        font-family: 'Consolas', 'Monaco', monospace;
        font-size: 13px;
      }
    }
    
    // 实体高亮样式 - 匹配原型 UI（边框 + 背景）
    :deep(.entity-highlight) {
      display: inline;
      padding: 2px 8px;
      border-radius: 4px;
      cursor: pointer;
      transition: all 0.2s;
      font-weight: 500;
      border: 1px solid #1890ff;
      color: #1890ff;
      background: rgba(24, 144, 255, 0.1);
      
      &:hover {
        background: #1890ff;
        color: white;
      }
      
      // 实体类型颜色
      &.entity {
        border-color: #1890ff;
        color: #1890ff;
        background: rgba(24, 144, 255, 0.1);
        &:hover { background: #1890ff; color: white; }
      }
      
      &.concept {
        border-color: #722ed1;
        color: #722ed1;
        background: rgba(114, 46, 209, 0.1);
        &:hover { background: #722ed1; color: white; }
      }
      
      &.data {
        border-color: #52c41a;
        color: #52c41a;
        background: rgba(82, 196, 26, 0.1);
        &:hover { background: #52c41a; color: white; }
      }
      
      &.location {
        border-color: #faad14;
        color: #d48806;
        background: rgba(250, 173, 20, 0.1);
        &:hover { background: #faad14; color: white; }
      }
      
      &.asset {
        border-color: #eb2f96;
        color: #eb2f96;
        background: rgba(235, 47, 150, 0.1);
        &:hover { background: #eb2f96; color: white; }
      }
      
      &.person {
        border-color: #1890ff;
        color: #1890ff;
        background: rgba(24, 144, 255, 0.1);
        &:hover { background: #1890ff; color: white; }
      }
      
      &.org {
        border-color: #722ed1;
        color: #722ed1;
        background: rgba(114, 46, 209, 0.1);
        &:hover { background: #722ed1; color: white; }
      }
      
      &.date {
        border-color: #13c2c2;
        color: #13c2c2;
        background: rgba(19, 194, 194, 0.1);
        &:hover { background: #13c2c2; color: white; }
      }
      
      &.product {
        border-color: #eb2f96;
        color: #eb2f96;
        background: rgba(235, 47, 150, 0.1);
        &:hover { background: #eb2f96; color: white; }
      }
      
      &.event {
        border-color: #fa8c16;
        color: #fa8c16;
        background: rgba(250, 140, 22, 0.1);
        &:hover { background: #fa8c16; color: white; }
      }
      
      &.law {
        border-color: #2f54eb;
        color: #2f54eb;
        background: rgba(47, 84, 235, 0.1);
        &:hover { background: #2f54eb; color: white; }
      }
    }
  }
}

.right-panel {
  width: 380px;
  background: #fff;
  border-left: 1px solid var(--border);
  overflow-y: auto;
  flex-shrink: 0;
}

.element-section {
  border-bottom: 1px solid var(--border);

  .element-header {
    padding: 14px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .element-title {
      font-size: 13px;
      font-weight: 600;

      .element-count {
        color: var(--text-3);
        font-weight: normal;
      }
    }
  }

  .element-filter {
    padding: 0 16px 12px;
    
    .entity-search {
      margin-bottom: 10px;
      
      :deep(.el-input__wrapper) {
        border-radius: 18px;
      }
    }
    
    .entity-type-filter {
      display: flex;
      flex-wrap: wrap;
      gap: 6px;
      
      .filter-tag {
        cursor: pointer;
        transition: all 0.2s;
        border-radius: 12px;
        font-size: 11px;
        
        &:hover {
          border-color: var(--primary);
          color: var(--primary);
        }
        
        &.active {
          background: var(--primary);
          color: white;
          border-color: var(--primary);
        }
        
        &.clear {
          background: transparent;
          border-style: dashed;
          color: var(--text-3);
          
          &:hover {
            border-color: var(--danger);
            color: var(--danger);
          }
        }
      }
    }
  }

  .element-body {
    padding: 0 16px 16px;
  }

  .element-tags-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    max-height: 280px;
    overflow-y: auto;
  }
  
  // 要素标签样式 - 匹配原型 UI
  .var-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 16px;
    font-size: 12px;
    cursor: grab;
    transition: all 0.2s;
    background: var(--bg);
    border: 1px solid var(--border);
    user-select: none;
    
    &:hover {
      border-color: var(--primary);
      background: var(--primary-light);
      transform: translateY(-1px);
    }
    
    &:active {
      cursor: grabbing;
    }
    
    .tag-icon {
      font-size: 12px;
    }
    
    .tag-name {
      max-width: 120px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      font-weight: 500;
    }
    
    .tag-status {
      color: #52c41a;
      font-size: 10px;
    }
    
    // 实体类型样式 - 左边框颜色区分
    &.entity-person, &.entity {
      border-left: 3px solid #1890ff;
    }
    &.entity-org, &.concept {
      border-left: 3px solid #722ed1;
    }
    &.entity-location, &.location {
      border-left: 3px solid #faad14;
    }
    &.entity-date {
      border-left: 3px solid #13c2c2;
    }
    &.entity-data, &.data {
      border-left: 3px solid #52c41a;
    }
    &.entity-product, &.asset {
      border-left: 3px solid #eb2f96;
    }
    &.entity-event {
      border-left: 3px solid #fa8c16;
    }
    &.entity-law {
      border-left: 3px solid #2f54eb;
    }
    &.entity-default {
      border-left: 3px solid #8c8c8c;
    }
  }

  .element-hint {
    font-size: 12px;
    color: var(--text-3);
    text-align: center;
    padding: 20px;
  }
}

// 实体高亮闪烁效果
@keyframes entity-flash {
  0%, 100% { background-color: inherit; }
  50% { background-color: #ffe58f; }
}

.entity-highlight-flash {
  animation: entity-flash 0.5s ease-in-out 3;
}

.category-section {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);

  .category-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 10px;

    .category-dot {
      width: 10px;
      height: 10px;
      border-radius: 50%;
    }

    .category-count {
      color: var(--text-3);
      font-weight: normal;
      background: var(--bg);
      padding: 2px 8px;
      border-radius: 10px;
    }
  }

  .category-items {
    .category-item {
      display: flex;
      justify-content: space-between;
      padding: 8px 12px;
      background: var(--bg);
      border-radius: 6px;
      margin-bottom: 6px;
      cursor: pointer;
      font-size: 12px;
      transition: all 0.2s;

      &:hover {
        background: var(--primary-light);
      }

      .item-value {
        color: var(--text-3);
      }
    }
  }
}

.context-menu {
  position: fixed;
  min-width: 180px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  z-index: 3000;
  overflow: hidden;

  .context-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    font-size: 13px;
    cursor: pointer;
    transition: all 0.15s;

    &:hover {
      background: var(--primary-light);
      color: var(--primary);
    }

    .icon {
      font-size: 14px;
    }
  }
}

.graph-container {
  height: 500px;
  position: relative;
  background: linear-gradient(135deg, #f8fafc 0%, #f0f4f8 100%);
  border-radius: 8px;

  .graph-legend {
    position: absolute;
    top: 16px;
    left: 16px;
    background: #fff;
    border-radius: 8px;
    padding: 12px 16px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

    .legend-title {
      font-size: 12px;
      font-weight: 600;
      margin-bottom: 8px;
      color: var(--text-2);
    }

    .legend-item {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 11px;
      color: var(--text-2);
      margin-bottom: 4px;
    }

    .legend-dot {
      width: 12px;
      height: 12px;
      border-radius: 50%;

      &.entity { background: var(--primary); }
      &.concept { background: #722ed1; }
      &.data { background: var(--success); }
      &.location { background: var(--warning); }
    }
  }

  .graph-body {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;

    .graph-placeholder {
      text-align: center;
      color: var(--text-3);

      p {
        margin-top: 12px;
      }
    }
  }
}

// 空白编辑器占位提示样式
:deep(.empty-editor-placeholder) {
  padding: 60px 40px;
  text-align: center;
  color: var(--text-2);

  h2 {
    font-size: 24px;
    margin-bottom: 20px;
    color: var(--text-1);
  }

  p {
    font-size: 15px;
    margin-bottom: 16px;
  }

  ul {
    list-style: none;
    padding: 0;
    text-align: left;
    max-width: 300px;
    margin: 0 auto;

    li {
      padding: 8px 0;
      padding-left: 24px;
      position: relative;
      font-size: 14px;

      &::before {
        content: '✓';
        position: absolute;
        left: 0;
        color: var(--primary);
      }
    }
  }
}
</style>
