"use client"

import { useEffect, useRef, useState, forwardRef, useImperativeHandle, memo, useCallback } from "react"
import * as d3 from "d3"
// @ts-ignore - d3-org-chart没有TypeScript类型定义
import { OrgChart } from "d3-org-chart"
import { Download, FileText, UserPlus, Users, Baby } from "lucide-react"
import type { FamilyMember } from "@/types/family"
import jsPDF from "jspdf"
import { useRouter } from "next/navigation"
import { useFamily } from "@/context/family-context"
import { GenerationWarningDialog } from "@/components/tree/generation-warning-dialog"
import { shouldShowGenerationWarning } from "@/lib/generation-utils"

// 全局类型声明
declare global {
  interface Window {
    d3ChartContextMenu?: (event: MouseEvent, memberId: string) => void
    d3ChartSpouseClick?: (event: Event, spouseId: string) => void
  }
}

interface D3OrgChartFlowProps {
  members: Record<string, FamilyMember>
  rootId: string
  onMemberClick?: (memberId: string) => void
  onExport?: () => void
  relationMode?: boolean
  selectedMembers?: string[]
}

export interface D3OrgChartRef {
  exportPNG: () => void
  exportPDF: () => void
  expandAll: () => void
  collapseAll: () => void
  fitView: () => void
}

interface SpouseData {
  id: string
  name: string
  avatarUrl: string | null | undefined
  gender: string
  birthYear: string
  deathYear: string
  ageText: string
}

interface ChartNode {
  id: string
  parentId: string | null
  name: string
  generation: string
  birthYear: string
  deathYear: string
  birthPlace: string
  gender: string
  avatarUrl: string | null | undefined
  spouseName: string
  spouseId: string | null
  spouseAvatarUrl?: string | null
  spouseGender?: string | null
  spouseDeathYear?: string | null
  spouseBirthYear?: string | null
  spouseAgeText?: string
  // 多配偶支持
  spouses: SpouseData[]
  spouseCount: number
  hasChildren: boolean
  ageText: string
  isFounder?: boolean
}

// 计算年龄
function calculateAge(birthDate?: string, deathDate?: string): number | null {
  if (!birthDate) return null
  
  const birth = new Date(birthDate)
  const end = deathDate ? new Date(deathDate) : new Date()
  
  let age = end.getFullYear() - birth.getFullYear()
  const monthDiff = end.getMonth() - birth.getMonth()
  
  if (monthDiff < 0 || (monthDiff === 0 && end.getDate() < birth.getDate())) {
    age--
  }
  
  return age
}

const D3OrgChartFlowComponent = forwardRef<D3OrgChartRef, D3OrgChartFlowProps>(
  ({ members, rootId, onMemberClick, onExport, relationMode = false, selectedMembers = [] }, ref) => {
  console.log('D3OrgChartFlow render, selectedMembers:', selectedMembers, 'relationMode:', relationMode)
  
  const chartRef = useRef<HTMLDivElement>(null)
  const chartInstanceRef = useRef<any>(null)
  const [isReady, setIsReady] = useState(false)
  const [avatarCache, setAvatarCache] = useState<Map<string, string>>(new Map())
  const [contextMenuNode, setContextMenuNode] = useState<FamilyMember | null>(null)
  const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 })
  const router = useRouter()
  const { currentTree } = useFamily()
  
  // 代数重新计算警告对话框状态
  const [showWarningDialog, setShowWarningDialog] = useState(false)
  const [pendingAddMember, setPendingAddMember] = useState<{ type: 'father' | 'mother', member: FamilyMember } | null>(null)

  // 构建新增成员的 URL
  const buildAddUrl = (type: 'father' | 'mother' | 'spouse' | 'child', member: FamilyMember) => {
    const params = new URLSearchParams()
    if (currentTree?.id) {
      params.set('treeId', currentTree.id)
    }
    
    switch (type) {
      case 'father':
        params.set('childId', member.id)
        params.set('gender', 'MALE')
        // 如果是第1代成员，新父母的世代也设为1（后端会重新计算所有成员世代）
        params.set('generation', member.generation === 1 ? '1' : (member.generation - 1).toString())
        // 如果已有母亲，设为配偶
        if (member.motherId) {
          params.set('spouseId', member.motherId)
        }
        break
      case 'mother':
        params.set('childId', member.id)
        params.set('gender', 'FEMALE')
        // 如果是第1代成员，新父母的世代也设为1（后端会重新计算所有成员世代）
        params.set('generation', member.generation === 1 ? '1' : (member.generation - 1).toString())
        // 如果已有父亲，设为配偶
        if (member.fatherId) {
          params.set('spouseId', member.fatherId)
        }
        break
      case 'spouse':
        params.set('spouseId', member.id)
        params.set('generation', member.generation.toString())
        // 配偶性别与当前成员相反
        params.set('gender', member.gender === 'MALE' ? 'FEMALE' : 'MALE')
        
        // 如果当前成员有子女，将他们也作为新配偶的子女
        if (member.childrenIds && member.childrenIds.length > 0) {
          // 传递所有子女ID
          member.childrenIds.forEach(id => {
            params.append('childrenIds', id)
          })
        }
        break
      case 'child':
        // 根据当前成员性别设置父/母
        if (member.gender === 'MALE') {
          params.set('fatherId', member.id)
          // 如果父亲有配偶，设置配偶为母亲
          if (member.spouseIds && member.spouseIds.length > 0) {
            params.set('motherId', member.spouseIds[0])
          }
        } else {
          params.set('motherId', member.id)
          // 如果母亲有配偶，设置配偶为父亲
          if (member.spouseIds && member.spouseIds.length > 0) {
            params.set('fatherId', member.spouseIds[0])
          }
        }
        params.set('generation', (member.generation + 1).toString())
        break
    }
    
    return `/members/new?${params.toString()}`
  }

  const handleAddMember = (type: 'father' | 'mother' | 'spouse' | 'child', member: FamilyMember) => {
    // 检查是否需要显示代数重新计算警告
    if ((type === 'father' || type === 'mother') && shouldShowGenerationWarning(member, type)) {
      setPendingAddMember({ type, member })
      setShowWarningDialog(true)
      return
    }
    
    const url = buildAddUrl(type, member)
    console.log('D3 handleAddMember called:', type, url)
    // 使用 setTimeout 延迟跳转，确保菜单关闭后再执行
    setTimeout(() => {
      console.log('Navigating to:', url)
      window.location.href = url
    }, 100)
  }
  
  // 确认添加父母后的处理
  const handleConfirmAddParent = () => {
    if (pendingAddMember) {
      const url = buildAddUrl(pendingAddMember.type, pendingAddMember.member)
      console.log('Confirmed add parent, navigating to:', url)
      setTimeout(() => {
        window.location.href = url
      }, 100)
      setPendingAddMember(null)
    }
  }

  // 判断可以添加的关系
  const canAddFather = (member: FamilyMember) => !member.fatherId
  const canAddMother = (member: FamilyMember) => !member.motherId
  const canAddSpouse = (member: FamilyMember) => true // 配偶总是可以添加
  const canAddChild = (member: FamilyMember) => true // 子女总是可以添加

  // 转换数据格式
  const convertToChartData = (): ChartNode[] => {
    const chartNodes: ChartNode[] = []
    
    // 首先找到根节点（没有父节点的节点）
    const rootMember = members[rootId]
    if (!rootMember) return []
    
    // 使用BFS遍历，确保只包含从rootId开始的树
    const visited = new Set<string>()
    const queue: string[] = [rootId]
    
    while (queue.length > 0) {
      const currentId = queue.shift()!
      if (visited.has(currentId)) continue
      
      visited.add(currentId)
      const member = members[currentId]
      if (!member) continue
      
      // 获取所有配偶信息，确保配偶存在于members中
      const spouses = member.spouseIds
        ?.map(id => members[id])
        .filter(Boolean) || []
      
      // 确定父节点ID - 只有根节点的parentId为null
      // 重要：parentId 必须指向已经在 visited 集合中的节点，否则 d3-org-chart 会报 missing 错误
      let parentId: string | null = null
      if (currentId !== rootId) {
        // 根据姓氏判断主线，优先选择同姓的父母
        // 同时确保父母已经被访问过（在 visited 中）
        const father = member.fatherId && visited.has(member.fatherId) ? members[member.fatherId] : null
        const mother = member.motherId && visited.has(member.motherId) ? members[member.motherId] : null
        
        // 判断父母中谁是家族主线（同姓）
        const isFatherMainLine = father && member.surname === father.surname
        const isMotherMainLine = mother && member.surname === mother.surname
        
        if (isFatherMainLine) {
          parentId = member.fatherId || null
        } else if (isMotherMainLine) {
          parentId = member.motherId || null
        } else if (father) {
          // 如果都不同姓，优先选择父亲
          parentId = member.fatherId || null
        } else if (mother) {
          parentId = member.motherId || null
        }
      }
      
      // 计算年龄文本
      const age = calculateAge(member.birthDate, member.deathDate)
      const ageText = age !== null
        ? member.deathDate
          ? `享年${age}岁`
          : `${age}岁`
        : ''
      
      // 处理多配偶数据
      const spousesData = spouses.map(sp => ({
        id: sp.id,
        name: sp.fullName,
        avatarUrl: sp.avatarUrl,
        gender: sp.gender === 'MALE' ? '男' : '女',
        birthYear: sp.birthDate ? new Date(sp.birthDate).getFullYear().toString() : '',
        deathYear: sp.deathDate ? new Date(sp.deathDate).getFullYear().toString() : '',
        ageText: (() => {
          const age = calculateAge(sp.birthDate, sp.deathDate)
          return age !== null ? (sp.deathDate ? `享年${age}岁` : `${age}岁`) : ''
        })()
      }))
      
      chartNodes.push({
        id: member.id,
        parentId: parentId,
        name: member.fullName,
        generation: `第${member.generation}世`,
        birthYear: member.birthDate ? new Date(member.birthDate).getFullYear().toString() : '',
        deathYear: member.deathDate ? new Date(member.deathDate).getFullYear().toString() : '',
        birthPlace: member.birthPlace || '',
        gender: member.gender === 'MALE' ? '男' : '女',
        avatarUrl: member.avatarUrl,
        // 保留旧字段兼容
        spouseName: spouses.length > 0 ? spouses.map(s => s.fullName).join(', ') : '',
        spouseId: spouses.length > 0 ? spouses[0].id : null,
        spouseAvatarUrl: spouses.length > 0 ? spouses[0].avatarUrl : null,
        spouseGender: spouses.length > 0 ? (spouses[0].gender === 'MALE' ? '男' : '女') : null,
        spouseDeathYear: spouses.length > 0 ? (spouses[0].deathDate ? new Date(spouses[0].deathDate).getFullYear().toString() : '') : null,
        spouseBirthYear: spouses.length > 0 ? (spouses[0].birthDate ? new Date(spouses[0].birthDate).getFullYear().toString() : '') : null,
        spouseAgeText: spouses.length > 0 ? (() => {
          const sp = spouses[0]
          const age = calculateAge(sp.birthDate, sp.deathDate)
          return age !== null ? (sp.deathDate ? `享年${age}岁` : `${age}岁`) : ''
        })() : '',
        // 新增多配偶数组
        spouses: spousesData,
        spouseCount: spouses.length,
        hasChildren: Object.values(members).some(m => m.fatherId === member.id || m.motherId === member.id),
        ageText: ageText,
        isFounder: member.id === rootId  // 使用 rootId 判断始祖
      })
      
      // 添加子节点到队列
      Object.values(members).forEach(m => {
        if ((m.fatherId === currentId || m.motherId === currentId) && !visited.has(m.id)) {
          queue.push(m.id)
        }
      })
    }
    
    return chartNodes
  }

  // 构建头像缓存（URL 直接使用）
  useEffect(() => {
    const cache = new Map<string, string>()
    
    for (const member of Object.values(members)) {
      if (member.avatarUrl) {
        cache.set(member.avatarUrl, member.avatarUrl)
      }
    }
    
    setAvatarCache(cache)
  }, [members])

  useEffect(() => {
    if (!chartRef.current || !rootId) return

    // 清理旧的图表
    if (chartRef.current) {
      chartRef.current.innerHTML = ''
    }

    // iOS/iPadOS 检测（包括 Safari、Chrome 等所有浏览器）
    // iPad 上所有浏览器都使用 WebKit 引擎
    const container = chartRef.current
    const isTouchDevice = navigator.maxTouchPoints > 1
    const isWebKit = /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent)
    const isIOSChrome = /CriOS/.test(navigator.userAgent)
    const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || 
                  (navigator.platform === 'MacIntel' && isTouchDevice) ||
                  isIOSChrome
    
    console.log('Device detection:', { isIOS, isTouchDevice, isWebKit, isIOSChrome, userAgent: navigator.userAgent })
    
    // 对于 iOS，设置明确的像素高度
    if (isIOS) {
      const headerHeight = 120
      const calculatedHeight = window.innerHeight - headerHeight
      container.style.height = `${calculatedHeight}px`
    }

    const data = convertToChartData()
    
    // 获取容器实际尺寸 - iOS Safari 可能返回 0，所以使用 window 尺寸作为后备
    const containerRect = chartRef.current.getBoundingClientRect()
    let containerWidth = containerRect.width
    let containerHeight = containerRect.height
    
    // 如果尺寸无效，使用 window 尺寸
    if (!containerWidth || containerWidth < 100) {
      containerWidth = window.innerWidth
    }
    if (!containerHeight || containerHeight < 100) {
      containerHeight = window.innerHeight - 120
    }
    
    console.log('D3 Chart container size:', { containerWidth, containerHeight, isIOS })
    
    // 初始化图表
    const chart = new OrgChart()
      .container(chartRef.current)
      .data(data)
      .svgWidth(containerWidth)
      .svgHeight(containerHeight)
      .scaleExtent([0.1, 2]) // 缩放范围
      .initialZoom(0.5) // 初始缩放级别
      .nodeWidth((d: any) => {
        const spouseCount = d.data.spouseCount || 0
        return spouseCount === 0 ? 170 : spouseCount === 1 ? 300 : 170 + spouseCount * 110
      }) // 根据配偶数量动态调整宽度
      .nodeHeight(() => 175)
      .childrenMargin(() => 50)
      .compactMarginBetween(() => 20) // 减少间距
      .compactMarginPair(() => 20)
      .neighbourMargin(() => 20)
      .siblingsMargin(() => 20)
      .linkUpdate(function (d: any, i: any, arr: any) {
        // 现代风格连线 - 使用柔和的灰蓝色
        d3.select(arr[i])
          .attr('stroke', '#94a3b8')
          .attr('stroke-width', 2)
          .attr('stroke-dasharray', '')
          .style('opacity', 0.6)
      })
      .buttonContent(({ node }: any) => {
        return `<div style="
          color: #64748b;
          border-radius: 20px;
          padding: 4px 10px;
          font-size: 11px;
          font-weight: 500;
          margin: auto;
          background: white;
          border: 1px solid #e2e8f0;
          box-shadow: 0 2px 8px rgba(0,0,0,0.08);
          display: flex;
          align-items: center;
          gap: 4px;
          transition: all 0.2s;
        " onmouseover="this.style.boxShadow='0 4px 12px rgba(0,0,0,0.12)'" onmouseout="this.style.boxShadow='0 2px 8px rgba(0,0,0,0.08)'">
          <span style="font-size: 10px;">${node.children ? '▲' : '▼'}</span>
          <span>${node.data._directSubordinates || 0}</span>
        </div>`
      })
      .nodeContent((d: any) => {
        const node = d.data
        const isMale = node.gender === '男'
        const isDead = !!node.deathYear
        const hasSpouse = !!node.spouseId
        const isFounder = node.isFounder === true
        
        // 现代简约风格配色
        const topBarGradient = isFounder 
          ? 'linear-gradient(to right, #f59e0b, #ea580c, #f59e0b)'
          : isDead 
            ? 'linear-gradient(to right, #78716c, #57534e, #78716c)' 
            : isMale 
              ? 'linear-gradient(to right, #38bdf8, #3b82f6, #38bdf8)'
              : 'linear-gradient(to right, #fb7185, #ec4899, #fb7185)'
          
        const bgGradient = isFounder
          ? 'linear-gradient(135deg, #fffbeb, #fef3c7, #fef9c3)'
          : isDead 
            ? 'linear-gradient(135deg, #f5f5f4, #e7e5e4, #f5f5f4)'
            : isMale 
              ? 'linear-gradient(135deg, #f0f9ff, #e0f2fe, #ecfeff)'
              : 'linear-gradient(135deg, #fff1f2, #fce7f3, #fdf2f8)'
              
        const avatarBorder = isFounder 
          ? '#f59e0b'
          : isDead ? '#a8a29e' : isMale ? '#38bdf8' : '#fb7185'
        
        const avatarGlow = isFounder 
          ? 'rgba(245, 158, 11, 0.4)'
          : isDead ? 'rgba(168, 162, 158, 0.3)' : isMale ? 'rgba(56, 189, 248, 0.4)' : 'rgba(251, 113, 133, 0.4)'
          
        const textColor = '#000000' // 纯黑色文字
        
        const badgeGradient = isFounder
          ? 'linear-gradient(to right, #f59e0b, #ea580c)'
          : isDead 
            ? 'linear-gradient(to right, #78716c, #57534e)'
            : isMale 
              ? 'linear-gradient(to right, #38bdf8, #3b82f6)'
              : 'linear-gradient(to right, #fb7185, #ec4899)'
        
        // 获取头像URL
        const avatarUrl = node.avatarUrl ? avatarCache.get(node.avatarUrl) : null
        
        // 检查是否被选中
        const isSelected = selectedMembers.includes(node.id)
        
        // 多配偶数据
        const spousesArray = node.spouses || []
        const spouseCount = spousesArray.length
        
        // 动态宽度：根据配偶数量调整
        const width = spouseCount === 0 ? 150 : spouseCount === 1 ? 280 : 150 + spouseCount * 100
        
        return `
          <div 
            data-member-id="${node.id}"
            style="
              position: relative;
              width: ${width}px;
              height: 160px;
              box-sizing: border-box;
              background: ${bgGradient};
              border-radius: 16px;
              padding: 16px 12px 12px;
              box-shadow: 0 4px 20px rgba(0,0,0,0.08);
              cursor: pointer;
              transition: all 0.3s ease;
              -webkit-transform: translateZ(0);
              transform: translateZ(0);
            " 
            onmouseover="this.style.boxShadow='0 12px 40px rgba(0,0,0,0.15)'; this.style.transform='translateY(-4px) scale(1.02)'" 
            onmouseout="this.style.boxShadow='0 4px 20px rgba(0,0,0,0.08)'; this.style.transform='translateZ(0)'"
          >
            <!-- 顶部装饰条 -->
            <div style="
              position: absolute;
              top: 0;
              left: 16px;
              right: 16px;
              height: 4px;
              background: ${topBarGradient};
              border-radius: 0 0 4px 4px;
            "></div>
            
            <!-- 世代标签 - 胶囊风格 -->
            <div style="
              position: absolute;
              top: -10px;
              left: 50%;
              transform: translateX(-50%);
              background: ${badgeGradient};
              color: white;
              font-size: 10px;
              font-weight: 500;
              padding: 3px 12px;
              border-radius: 20px;
              box-shadow: 0 2px 8px rgba(0,0,0,0.15);
              z-index: 10;
              letter-spacing: 1px;
            ">
              ${node.generation}
            </div>
            
            <!-- 选中标记 -->
            ${isSelected ? `
              <div style="position: absolute; top: 8px; left: 8px; z-index: 20;">
                <div style="width: 20px; height: 20px; border-radius: 50%; background: #3b82f6; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(59,130,246,0.4);">
                  <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                </div>
              </div>
            ` : ''}
            
            <div style="display: flex; justify-content: center; gap: 16px; margin-top: 8px;">
              <!-- 主成员 -->
              <div style="display: flex; flex-direction: column; align-items: center; gap: 8px; flex: 1;">
                <!-- 头像带光晕 -->
                <div style="position: relative;">
                  <div style="
                    position: absolute;
                    inset: -2px;
                    border-radius: 50%;
                    background: ${avatarGlow};
                    filter: blur(8px);
                  "></div>
                  <div style="
                    position: relative;
                    width: 52px;
                    height: 52px;
                    border-radius: 50%;
                    background: white;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    overflow: hidden;
                    border: 3px solid ${avatarBorder};
                    box-shadow: 0 4px 12px rgba(0,0,0,0.1), inset 0 0 0 2px white;
                  ">
                    ${avatarUrl 
                      ? `<img src="${avatarUrl}" alt="${node.name}" style="width: 100%; height: 100%; object-fit: cover;" />`
                      : node.gender === '女'
                        ? `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="${isDead ? '#a8a29e' : '#ec4899'}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 20a6 6 0 0 0-12 0"/><circle cx="12" cy="10" r="4"/><circle cx="12" cy="12" r="10"/></svg>`
                        : `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="${isDead ? '#a8a29e' : '#3b82f6'}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="10" r="3"/><path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662"/></svg>`
                    }
                  </div>
                  <!-- 状态指示器 -->
                  <div style="
                    position: absolute;
                    bottom: 0;
                    right: 0;
                    width: 14px;
                    height: 14px;
                    border-radius: 50%;
                    background: ${isDead ? '#a8a29e' : '#22c55e'};
                    border: 2px solid white;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                  "></div>
                </div>
                
                <!-- 姓名 -->
                <div style="
                  font-size: 15px;
                  font-weight: 600;
                  color: ${textColor};
                  letter-spacing: 0.5px;
                  white-space: nowrap;
                  font-family: serif;
                ">
                  ${node.name}
                </div>
                
                <!-- 生卒信息 -->
                <div style="text-align: center;">
                  ${node.birthYear ? `
                    <div style="
                      font-size: 10px;
                      color: #000000;
                      font-family: serif;
                      background: ${isDead ? 'rgba(168,162,158,0.3)' : 'rgba(107,114,128,0.2)'};
                      padding: 2px 8px;
                      border-radius: 10px;
                      display: inline-block;
                      font-weight: 500;
                    ">
                      ${node.birthYear}${node.deathYear ? ` — ${node.deathYear}` : ' —'}
                    </div>
                    ${node.ageText ? `<div style="font-size: 10px; color: #000000; margin-top: 2px; font-weight: 500; font-family: serif;">${node.ageText}</div>` : ''}
                  ` : ''}
                </div>
              </div>
              
              <!-- 配偶们 -->
              ${spousesArray.map((sp: any, idx: number) => {
                const spIsMale = sp.gender === '男'
                const spIsDead = !!sp.deathYear
                const spAvatarBorder = spIsDead ? '#a8a29e' : spIsMale ? '#38bdf8' : '#fb7185'
                const spAvatarGlow = spIsDead ? 'rgba(168, 162, 158, 0.3)' : spIsMale ? 'rgba(56, 189, 248, 0.4)' : 'rgba(251, 113, 133, 0.4)'
                const spAvatarUrl = sp.avatarUrl ? avatarCache.get(sp.avatarUrl) : null
                
                return `
                <div 
                  class="spouse-area"
                  data-spouse-id="${sp.id}"
                  style="display: flex; flex-direction: column; align-items: center; gap: 6px; cursor: pointer; position: relative; min-width: 80px;"
                  onclick="event.stopPropagation(); window.d3ChartSpouseClick && window.d3ChartSpouseClick(event, '${sp.id}')"
                >
                  ${idx === 0 ? `
                  <!-- 连接线 -->
                  <div style="
                    position: absolute;
                    left: -8px;
                    top: 22px;
                    width: 16px;
                    height: 2px;
                    background: linear-gradient(to right, ${avatarBorder}, ${spAvatarBorder});
                    border-radius: 1px;
                  "></div>
                  ` : ''}
                  
                  <!-- 头像带光晕 -->
                  <div style="position: relative;">
                    <div style="
                      position: absolute;
                      inset: -2px;
                      border-radius: 50%;
                      background: ${spAvatarGlow};
                      filter: blur(6px);
                    "></div>
                    <div style="
                      position: relative;
                      width: 44px;
                      height: 44px;
                      border-radius: 50%;
                      background: white;
                      display: flex;
                      align-items: center;
                      justify-content: center;
                      overflow: hidden;
                      border: 2px solid ${spAvatarBorder};
                      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
                    ">
                      ${spAvatarUrl 
                        ? `<img src="${spAvatarUrl}" alt="${sp.name}" style="width: 100%; height: 100%; object-fit: cover;" />`
                        : spIsMale
                          ? `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="${spIsDead ? '#a8a29e' : '#3b82f6'}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="10" r="3"/><path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662"/></svg>`
                          : `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="${spIsDead ? '#a8a29e' : '#ec4899'}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 20a6 6 0 0 0-12 0"/><circle cx="12" cy="10" r="4"/><circle cx="12" cy="12" r="10"/></svg>`
                      }
                    </div>
                    <!-- 状态指示器 -->
                    <div style="
                      position: absolute;
                      bottom: -1px;
                      right: -1px;
                      width: 12px;
                      height: 12px;
                      border-radius: 50%;
                      background: ${spIsDead ? '#a8a29e' : '#22c55e'};
                      border: 2px solid white;
                    "></div>
                  </div>
                  
                  <!-- 姓名 -->
                  <div style="
                    font-size: 12px;
                    font-weight: 600;
                    color: #000000;
                    white-space: nowrap;
                    font-family: serif;
                  ">
                    ${sp.name}
                  </div>
                  
                  <!-- 生卒信息 -->
                  ${sp.birthYear ? `
                  <div style="
                    font-size: 9px;
                    color: #000000;
                    font-family: serif;
                    background: ${spIsDead ? 'rgba(168,162,158,0.3)' : 'rgba(107,114,128,0.2)'};
                    padding: 1px 6px;
                    border-radius: 8px;
                    font-weight: 500;
                  ">
                    ${sp.birthYear}${sp.deathYear ? `-${sp.deathYear}` : '-'}
                  </div>
                  ${sp.ageText ? `<div style="font-size: 9px; color: #000000; margin-top: 2px; font-weight: 500; font-family: serif;">${sp.ageText}</div>` : ''}
                  ` : ''}
                </div>
                `
              }).join('')}
            </div>
          </div>
        `
      })
      .onNodeClick((d: any) => {
        if (onMemberClick && d) {
          // d3-org-chart传递的是节点数据对象，需要提取id
          const nodeId = typeof d === 'string' ? d : (d.data?.id || d.id)
          if (nodeId) {
            onMemberClick(nodeId)
          }
        }
      })
      .render()
      .expandAll() // 初始化时展开所有节点
      .fit() // 自适应全图显示

    // 延迟再次 fit
    setTimeout(() => chart.fit(), 100)
    setTimeout(() => chart.fit(), 300)
    
    // 所有触摸设备都需要特殊处理 - iOS foreignObject bug 修复
    if (isTouchDevice) {
      setTimeout(() => {
        const w = window.innerWidth
        const h = window.innerHeight - 120
        
        if (chartRef.current) {
          chartRef.current.style.height = `${h}px`
          chartRef.current.style.width = `${w}px`
          
          // iOS foreignObject bug 修复：强制重绘 SVG
          const svg = chartRef.current.querySelector('svg')
          if (svg) {
            // 触发重绘
            svg.style.display = 'none'
            void (svg as any).getBBox() // 强制回流
            svg.style.display = ''
          }
        }
        
        // 重新设置 SVG 尺寸并渲染
        chart.svgWidth(w).svgHeight(h).render().expandAll().fit()
        console.log('Touch device delayed render:', { w, h })
      }, 500)
      
      // 再次强制重绘
      setTimeout(() => {
        if (chartRef.current) {
          const svg = chartRef.current.querySelector('svg')
          if (svg) {
            svg.style.transform = 'translateZ(0)'
            // 强制所有 foreignObject 重新定位
            const foreignObjects = svg.querySelectorAll('foreignObject')
            foreignObjects.forEach((fo: Element) => {
              (fo as HTMLElement).style.transform = 'translateZ(0)'
            })
          }
        }
        chart.fit()
      }, 1000)
      
      setTimeout(() => chart.fit(), 1500)
    }

    // 注册全局配偶点击处理函数
    window.d3ChartSpouseClick = (event: Event, spouseId: string) => {
      event.stopPropagation()
      if (spouseId && onMemberClick) {
        onMemberClick(spouseId)
      }
    }

    // 添加右键菜单支持
    setTimeout(() => {
      const nodes = chartRef.current?.querySelectorAll('[data-member-id]')
      console.log('Found nodes for context menu:', nodes?.length)
      nodes?.forEach((node) => {
        const memberId = (node as HTMLElement).getAttribute('data-member-id')
        if (memberId) {
          node.addEventListener('contextmenu', (e) => {
            e.preventDefault()
            const mouseEvent = e as MouseEvent
            const member = members[memberId]
            if (member && !relationMode) {
              console.log('Right click on member:', member.fullName, 'at', mouseEvent.clientX, mouseEvent.clientY)
              setContextMenuNode(member)
              setContextMenuPosition({ x: mouseEvent.clientX, y: mouseEvent.clientY })
            }
          })
        }
      })
    }, 200)

    chartInstanceRef.current = chart
    setIsReady(true)

    return () => {
      // 清理
      if (chartRef.current) {
        chartRef.current.innerHTML = ''
      }
      // 清理全局函数
      if (window.d3ChartContextMenu) {
        delete window.d3ChartContextMenu
      }
      if (window.d3ChartSpouseClick) {
        delete window.d3ChartSpouseClick
      }
    }
  }, [members, rootId, onMemberClick, avatarCache])

  // 监听窗口大小变化，重新适应视图
  useEffect(() => {
    const handleResize = () => {
      if (chartInstanceRef.current) {
        // 延迟执行 fit，等待布局稳定
        setTimeout(() => {
          chartInstanceRef.current?.fit()
        }, 100)
      }
    }

    window.addEventListener('resize', handleResize)
    // 监听屏幕方向变化（iPad 等设备）
    window.addEventListener('orientationchange', handleResize)

    return () => {
      window.removeEventListener('resize', handleResize)
      window.removeEventListener('orientationchange', handleResize)
    }
  }, [])

  // 监听 selectedMembers 变化，通过 DOM 操作更新选中标记
  useEffect(() => {
    console.log('Selection useEffect triggered, selectedMembers:', selectedMembers, 'isReady:', isReady)
    if (!chartRef.current || !isReady) return
    
    // 移除所有现有的选中标记
    const existingMarks = chartRef.current.querySelectorAll('.selection-mark')
    existingMarks.forEach(mark => mark.remove())
    
    // 为选中的成员添加选中标记（只打钩，不改变边框和背景）
    selectedMembers.forEach(memberId => {
      console.log('Marking member as selected:', memberId)
      
      // 先尝试查找主成员节点
      const nodeElement = chartRef.current?.querySelector(`[data-member-id="${memberId}"]`)
      
      // 再尝试查找配偶区域
      const spouseElement = chartRef.current?.querySelector(`[data-spouse-id="${memberId}"]`)
      
      if (nodeElement) {
        // 主成员：只添加打钩标记（左边）
        const checkMark = document.createElement('div')
        checkMark.className = 'selection-mark'
        checkMark.style.cssText = 'position: absolute; top: 6px; left: 6px; z-index: 20;'
        checkMark.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="#2563eb" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="9 12 11 14 15 10" fill="none" stroke="white" stroke-width="2.5"/></svg>`
        nodeElement.appendChild(checkMark)
      } else if (spouseElement) {
        // 配偶：只添加打钩标记
        const checkMark = document.createElement('div')
        checkMark.className = 'selection-mark'
        checkMark.style.cssText = 'position: absolute; top: -5px; right: -5px; z-index: 20;'
        checkMark.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="#2563eb" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="9 12 11 14 15 10" fill="none" stroke="white" stroke-width="2.5"/></svg>`
        spouseElement.appendChild(checkMark)
      }
    })
  }, [selectedMembers, isReady])
  
  // 导出PNG
  const handleExportPNG = () => {
    if (!chartInstanceRef.current) return

    chartInstanceRef.current.exportImg({
      save: true,
      full: true,
      onLoad: () => {
        onExport?.()
      }
    })
  }

  // 导出PDF
  const handleExportPDF = () => {
    if (!chartInstanceRef.current) return

    chartInstanceRef.current.exportImg({
      save: false,
      full: true,
      onLoad: (base64: string) => {
        const pdf = new jsPDF({
          orientation: 'landscape',
          unit: 'px',
          format: 'a4'
        })
        
        const img = new Image()
        img.src = base64
        img.onload = function () {
          const imgWidth = img.width
          const imgHeight = img.height
          const pdfWidth = pdf.internal.pageSize.getWidth()
          const pdfHeight = pdf.internal.pageSize.getHeight()
          
          // 计算缩放比例以适应页面
          const ratio = Math.min(pdfWidth / imgWidth, pdfHeight / imgHeight)
          const scaledWidth = imgWidth * ratio
          const scaledHeight = imgHeight * ratio
          
          // 居中放置
          const x = (pdfWidth - scaledWidth) / 2
          const y = (pdfHeight - scaledHeight) / 2
          
          pdf.addImage(img, 'PNG', x, y, scaledWidth, scaledHeight)
          pdf.save(`家谱图-${new Date().toISOString().split('T')[0]}.pdf`)
          onExport?.()
        }
      }
    })
  }

  // 展开所有节点
  const handleExpandAll = () => {
    if (!chartInstanceRef.current) return
    chartInstanceRef.current.expandAll()
  }

  // 折叠所有节点
  const handleCollapseAll = () => {
    if (!chartInstanceRef.current) return
    chartInstanceRef.current.collapseAll()
  }

  // 适应视图
  const handleFitView = () => {
    if (!chartInstanceRef.current) return
    chartInstanceRef.current.fit()
  }

  // Minimap 状态
  const minimapRef = useRef<HTMLCanvasElement>(null)
  const [minimapExpanded, setMinimapExpanded] = useState(true)
  const minimapDataRef = useRef<{
    bbox: { x: number; y: number; width: number; height: number }
    mmScale: number
    offsetX: number
    offsetY: number
  } | null>(null)
  const isDraggingMinimapRef = useRef(false)

  // 更新 minimap（使用 Canvas 绘制）
  const updateMinimap = useCallback(() => {
    if (!minimapRef.current || !chartRef.current) return
    
    const canvas = minimapRef.current
    const ctx = canvas.getContext('2d')
    if (!ctx) return

    const mainSvg = chartRef.current.querySelector('svg')
    if (!mainSvg) return

    const mmW = 180, mmH = 130
    canvas.width = mmW
    canvas.height = mmH

    // 清空画布
    ctx.fillStyle = '#fafafa'
    ctx.fillRect(0, 0, mmW, mmH)

    // 直接从 SVG 中查找所有 foreignObject，不管它们在哪个 g 元素中
    const foreignObjects = mainSvg.querySelectorAll('foreignObject')
    if (foreignObjects.length === 0) return

    let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity
    
    // 收集节点位置数据 - 需要考虑父元素的 transform
    const nodePositions: { x: number; y: number; w: number; h: number }[] = []
    
    foreignObjects.forEach((fo) => {
      // 获取 foreignObject 的属性
      let x = parseFloat(fo.getAttribute('x') || '0')
      let y = parseFloat(fo.getAttribute('y') || '0')
      const w = parseFloat(fo.getAttribute('width') || '0')
      const h = parseFloat(fo.getAttribute('height') || '0')
      
      // 检查父元素是否有 transform（d3-org-chart 的节点通常在有 transform 的 g 元素中）
      const parentG = fo.parentElement
      if (parentG && parentG.tagName === 'g') {
        const parentTransform = parentG.getAttribute('transform')
        if (parentTransform) {
          const translateMatch = parentTransform.match(/translate\(\s*([^,\s]+)[,\s]+([^)\s]+)\s*\)/)
          if (translateMatch) {
            x += parseFloat(translateMatch[1])
            y += parseFloat(translateMatch[2])
          }
        }
      }
      
      if (w > 0 && h > 0) {
        nodePositions.push({ x, y, w, h })
        minX = Math.min(minX, x)
        minY = Math.min(minY, y)
        maxX = Math.max(maxX, x + w)
        maxY = Math.max(maxY, y + h)
      }
    })

    if (minX === Infinity || minY === Infinity || nodePositions.length === 0) return

    // 添加边距
    const padding = 20
    const contentX = minX - padding
    const contentY = minY - padding
    const contentW = (maxX - minX) + padding * 2
    const contentH = (maxY - minY) + padding * 2

    // 计算缩放比例，确保内容完全显示在 minimap 中
    const scaleX = (mmW - 8) / contentW
    const scaleY = (mmH - 8) / contentH
    const mmScale = Math.min(scaleX, scaleY)

    // 计算偏移使内容居中
    const offsetX = (mmW - contentW * mmScale) / 2 - contentX * mmScale
    const offsetY = (mmH - contentH * mmScale) / 2 - contentY * mmScale

    // 保存数据供点击使用（使用原始坐标系）
    minimapDataRef.current = { 
      bbox: { x: contentX, y: contentY, width: contentW, height: contentH },
      mmScale, 
      offsetX, 
      offsetY 
    }

    // 绘制连线（先画连线，再画节点）
    ctx.strokeStyle = '#cbd5e1'
    ctx.lineWidth = 1
    mainSvg.querySelectorAll('path').forEach((path) => {
      const d = path.getAttribute('d')
      // 跳过没有 d 属性或者是其他类型的 path
      if (!d || d.length < 5) return
      
      const path2D = new Path2D()
      const commands = d.match(/[MLHVCSQTAZ][^MLHVCSQTAZ]*/gi) || []
      commands.forEach(cmd => {
        const type = cmd[0].toUpperCase()
        const nums = cmd.slice(1).trim().split(/[\s,]+/).map(Number).filter(n => !isNaN(n))
        
        if (type === 'M' && nums.length >= 2) {
          path2D.moveTo(nums[0] * mmScale + offsetX, nums[1] * mmScale + offsetY)
        } else if (type === 'L' && nums.length >= 2) {
          path2D.lineTo(nums[0] * mmScale + offsetX, nums[1] * mmScale + offsetY)
        } else if (type === 'C' && nums.length >= 6) {
          path2D.bezierCurveTo(
            nums[0] * mmScale + offsetX, nums[1] * mmScale + offsetY,
            nums[2] * mmScale + offsetX, nums[3] * mmScale + offsetY,
            nums[4] * mmScale + offsetX, nums[5] * mmScale + offsetY
          )
        }
      })
      ctx.stroke(path2D)
    })

    // 绘制节点
    ctx.fillStyle = '#3b82f6'
    nodePositions.forEach(({ x, y, w, h }) => {
      const drawX = x * mmScale + offsetX
      const drawY = y * mmScale + offsetY
      const drawW = Math.max(w * mmScale, 4)
      const drawH = Math.max(h * mmScale, 3)
      
      ctx.beginPath()
      ctx.roundRect(drawX, drawY, drawW, drawH, 2)
      ctx.fill()
    })

    // 获取当前 transform - d3-org-chart 的 transform 在第一个 g 元素上
    const mainG = mainSvg.querySelector('g') as SVGGElement
    const transform = mainG?.getAttribute('transform') || ''
    const translateMatch = transform.match(/translate\(\s*([^,\s]+)[,\s]+([^)\s]+)\s*\)/)
    const scaleMatch = transform.match(/scale\(\s*([^)\s]+)\s*\)/)
    
    const tx = translateMatch ? parseFloat(translateMatch[1]) : 0
    const ty = translateMatch ? parseFloat(translateMatch[2]) : 0
    const k = scaleMatch ? parseFloat(scaleMatch[1]) : 1

    // 计算视口在原始坐标系中的位置
    const svgRect = mainSvg.getBoundingClientRect()
    const viewX = -tx / k
    const viewY = -ty / k
    const viewW = svgRect.width / k
    const viewH = svgRect.height / k

    // 绘制视口框
    const vpDrawX = viewX * mmScale + offsetX
    const vpDrawY = viewY * mmScale + offsetY
    const vpDrawW = viewW * mmScale
    const vpDrawH = viewH * mmScale

    ctx.strokeStyle = '#ef4444'
    ctx.lineWidth = 2
    ctx.fillStyle = 'rgba(239, 68, 68, 0.15)'
    ctx.beginPath()
    ctx.rect(vpDrawX, vpDrawY, vpDrawW, vpDrawH)
    ctx.fill()
    ctx.stroke()

  }, [])

  // 定时更新 minimap
  useEffect(() => {
    if (!minimapExpanded || !isReady) return

    const timer = setTimeout(updateMinimap, 500)
    const interval = setInterval(updateMinimap, 200)
    
    return () => {
      clearTimeout(timer)
      clearInterval(interval)
    }
  }, [minimapExpanded, isReady, updateMinimap])

  // 点击/拖拽 minimap 定位到具体位置
  const handleMinimapInteraction = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    if (!minimapDataRef.current || !chartRef.current || !chartInstanceRef.current) return
    
    const { mmScale, offsetX, offsetY } = minimapDataRef.current
    
    const canvas = e.currentTarget
    const rect = canvas.getBoundingClientRect()
    const clickX = e.clientX - rect.left
    const clickY = e.clientY - rect.top
    
    // 转换到原始坐标系
    const treeX = (clickX - offsetX) / mmScale
    const treeY = (clickY - offsetY) / mmScale
    
    // 获取主图
    const mainSvg = chartRef.current.querySelector('svg') as SVGSVGElement
    if (!mainSvg) return
    
    const mainG = mainSvg.querySelector('g')
    if (!mainG) return
    
    const svgRect = mainSvg.getBoundingClientRect()
    
    // 获取当前缩放级别
    const transform = mainG.getAttribute('transform') || ''
    const scaleMatch = transform.match(/scale\(\s*([^)\s]+)\s*\)/)
    const currentK = scaleMatch ? parseFloat(scaleMatch[1]) : 1
    
    // 计算新的 translate，使点击位置移动到视口中心
    const newTx = svgRect.width / 2 - treeX * currentK
    const newTy = svgRect.height / 2 - treeY * currentK
    
    // 直接修改 g 元素的 transform，不触发 d3-org-chart 的 zoom 事件
    // 这样可以避免触发 fit() 等操作
    const d3MainG = d3.select(mainG)
    if (isDraggingMinimapRef.current) {
      d3MainG.attr('transform', `translate(${newTx}, ${newTy}) scale(${currentK})`)
    } else {
      d3MainG.transition().duration(200)
        .attr('transform', `translate(${newTx}, ${newTy}) scale(${currentK})`)
    }
    
    // 同步 d3.zoom 的内部状态（重要！避免下次交互时状态不一致）
    const d3Svg = d3.select(mainSvg)
    const newTransform = d3.zoomIdentity.translate(newTx, newTy).scale(currentK)
    // @ts-ignore - 设置 zoom 的 __zoom 属性来同步状态
    mainSvg.__zoom = newTransform
  }, [])

  const handleMinimapMouseDown = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    isDraggingMinimapRef.current = true
    handleMinimapInteraction(e)
  }, [handleMinimapInteraction])

  const handleMinimapMouseMove = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    if (isDraggingMinimapRef.current) {
      handleMinimapInteraction(e)
    }
  }, [handleMinimapInteraction])

  const handleMinimapMouseUp = useCallback(() => {
    isDraggingMinimapRef.current = false
  }, [])

  // 暴露方法给父组件
  useImperativeHandle(ref, () => ({
    exportPNG: handleExportPNG,
    exportPDF: handleExportPDF,
    expandAll: handleExpandAll,
    collapseAll: handleCollapseAll,
    fitView: handleFitView,
  }))

  return (
    <div className="w-full h-full bg-[url('https://www.transparenttextures.com/patterns/rice-paper.png')] bg-repeat relative overflow-hidden" key={`d3-chart-${rootId}`}>
      {/* 图表容器 */}
      <div 
        ref={chartRef} 
        className="w-full h-full"
      />
      
      {/* Minimap */}
      {minimapExpanded ? (
        <div className="absolute bottom-20 right-4 z-20 md:bottom-4 bg-background/95 backdrop-blur rounded-lg border shadow-lg overflow-hidden">
          <div className="flex items-center justify-between px-2 py-1 border-b bg-muted/50">
            <span className="text-xs font-medium text-muted-foreground">缩略图</span>
            <button
              className="h-6 w-6 flex items-center justify-center hover:bg-accent rounded"
              onClick={() => setMinimapExpanded(false)}
              title="收起"
            >
              <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 14h6v6"/><path d="M20 10h-6V4"/><path d="m14 10 7-7"/><path d="m3 21 7-7"/></svg>
            </button>
          </div>
          <canvas 
            ref={minimapRef} 
            onMouseDown={handleMinimapMouseDown}
            onMouseMove={handleMinimapMouseMove}
            onMouseUp={handleMinimapMouseUp}
            onMouseLeave={handleMinimapMouseUp}
            style={{ display: 'block', cursor: 'crosshair' }} 
          />
        </div>
      ) : (
        <div className="absolute bottom-20 right-4 z-20 md:bottom-4">
          <button
            className="h-10 w-10 flex items-center justify-center bg-background/90 backdrop-blur shadow-lg border rounded-lg hover:bg-accent"
            onClick={() => setMinimapExpanded(true)}
            title="显示缩略图"
          >
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21"/><line x1="9" x2="9" y1="3" y2="18"/><line x1="15" x2="15" y1="6" y2="21"/></svg>
          </button>
        </div>
      )}
      {/* 自定义右键菜单 */}
      {contextMenuNode && (
        <div 
          className="fixed z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
          style={{ 
            left: contextMenuPosition.x, 
            top: contextMenuPosition.y,
            pointerEvents: 'auto'
          }}
          onClick={(e) => e.stopPropagation()}
        >
          <div className="px-2 py-1.5 text-sm text-muted-foreground">
            为 {contextMenuNode.fullName} 添加
          </div>
          <div className="h-px bg-border my-1" />
          
          {canAddFather(contextMenuNode) && (
            <div 
              className="relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground"
              onClick={() => {
                handleAddMember('father', contextMenuNode)
                setContextMenuNode(null)
              }}
            >
              <UserPlus className="h-4 w-4 text-blue-500" />
              添加父亲
            </div>
          )}
          
          {canAddMother(contextMenuNode) && (
            <div 
              className="relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground"
              onClick={() => {
                handleAddMember('mother', contextMenuNode)
                setContextMenuNode(null)
              }}
            >
              <UserPlus className="h-4 w-4 text-pink-500" />
              添加母亲
            </div>
          )}
          
          {(canAddFather(contextMenuNode) || canAddMother(contextMenuNode)) && (canAddSpouse(contextMenuNode) || canAddChild(contextMenuNode)) && (
            <div className="h-px bg-border my-1" />
          )}
          
          {canAddSpouse(contextMenuNode) && (
            <div 
              className="relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground"
              onClick={() => {
                handleAddMember('spouse', contextMenuNode)
                setContextMenuNode(null)
              }}
            >
              <Users className="h-4 w-4 text-red-500" />
              添加配偶
            </div>
          )}
          
          {canAddChild(contextMenuNode) && (
            <div 
              className="relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground"
              onClick={() => {
                handleAddMember('child', contextMenuNode)
                setContextMenuNode(null)
              }}
            >
              <Baby className="h-4 w-4 text-green-500" />
              添加子女
            </div>
          )}
        </div>
      )}
      
      {/* 点击其他地方关闭菜单 */}
      {contextMenuNode && (
        <div 
          className="fixed inset-0 z-40" 
          onClick={() => setContextMenuNode(null)}
        />
      )}
      
      {/* 代数重新计算警告对话框 */}
      {pendingAddMember && (
        <GenerationWarningDialog
          open={showWarningDialog}
          onOpenChange={setShowWarningDialog}
          memberName={pendingAddMember.member.fullName}
          relationType={pendingAddMember.type}
          onConfirm={handleConfirmAddParent}
        />
      )}
    </div>
  )
})

D3OrgChartFlowComponent.displayName = 'D3OrgChartFlow'

// 使用memo优化，避免不必要的重新渲染
export const D3OrgChartFlow = memo(D3OrgChartFlowComponent, (prevProps, nextProps) => {
  return prevProps.rootId === nextProps.rootId && 
         prevProps.members === nextProps.members
})
