<template>
  <div class="json-tree-node" :class="{ 'is-matched': isMatched, 'is-filtered': isFiltered }">
    <div
      class="node-line"
      :class="{ 'has-children': hasChildren, 'is-expanded': isExpanded, 'is-matched': isMatched }"
      @click="toggle"
    >
      <span v-if="hasChildren" class="expand-icon">
        <i :class="isExpanded ? 'fas fa-chevron-down' : 'fas fa-chevron-right'"></i>
      </span>
      <span v-else class="expand-placeholder"></span>
      <span v-if="showPath && nodePath" class="node-path">{{ nodePath }}:</span>
      <span class="node-key" v-if="key !== null">
        <span class="key-name" :class="{ 'matched': isMatched }">{{ key }}</span>:
      </span>
      <span class="node-value" :class="[valueType, { 'matched': isMatched }]">
        <span v-if="valueType === 'string'">"{{ displayValue }}"</span>
        <span v-else>{{ displayValue }}</span>
      </span>
    </div>
    <div v-if="hasChildren && isExpanded && shouldShowChildren" class="node-children">
      <JsonTreeNode
        v-for="(child, index) in filteredChildren"
        :key="index"
        :data="child.value"
        :key-name="child.key"
        :path="child.path"
        :expanded="expanded"
        :matched-paths="matchedPaths"
        :json-path-query="jsonPathQuery"
        @toggle="$emit('toggle', $event)"
      />
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  data: {
    type: [Object, Array, String, Number, Boolean, null],
    required: true
  },
  keyName: {
    type: [String, Number],
    default: null
  },
  path: {
    type: String,
    default: ''
  },
  expanded: {
    type: Set,
    required: true
  },
  matchedPaths: {
    type: Set,
    default: () => new Set()
  },
  jsonPathQuery: {
    type: String,
    default: ''
  },
  showPath: {
    type: Boolean,
    default: false
  },
  nodePath: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['toggle'])

const key = computed(() => props.keyName)
const currentPath = computed(() => {
  if (props.path === '' && props.keyName === null) {
    return 'root'
  }
  if (props.path === '') {
    return String(props.keyName)
  }
  if (props.path === 'root') {
    if (typeof props.keyName === 'number') {
      return `root[${props.keyName}]`
    }
    return `root.${props.keyName}`
  }
  if (typeof props.keyName === 'number') {
    return `${props.path}[${props.keyName}]`
  }
  return `${props.path}.${props.keyName}`
})

const hasChildren = computed(() => {
  return (
    (typeof props.data === 'object' && props.data !== null) ||
    Array.isArray(props.data)
  )
})

const isExpanded = computed(() => {
  return props.expanded.has(currentPath.value)
})

// 判断当前节点是否匹配 JSONPath
const isMatched = computed(() => {
  if (!props.jsonPathQuery || !props.jsonPathQuery.trim()) return false
  return props.matchedPaths.has(currentPath.value)
})

// 判断是否有筛选
const hasFilter = computed(() => {
  return props.jsonPathQuery && props.jsonPathQuery.trim() !== ''
})

// 判断是否应该显示子节点
const shouldShowChildren = computed(() => {
  if (!hasFilter.value) return true
  // 如果节点匹配，显示子节点（展开匹配节点的内容）
  if (isMatched.value) return true
  // 如果当前节点是匹配节点的子节点，显示所有子节点
  if (isChildOfMatched.value) return true
  // 检查是否有子节点匹配
  return hasMatchingChildren.value
})

// 检查是否有子节点匹配
const hasMatchingChildren = computed(() => {
  if (!hasFilter.value) return true
  if (!hasChildren.value) return false
  
  const basePath = props.path === '' && props.keyName === null ? 'root' : currentPath.value
  
  if (Array.isArray(props.data)) {
    return props.data.some((item, index) => {
      const childPath = `${basePath}[${index}]`
      return props.matchedPaths.has(childPath) || checkChildrenMatch(item, childPath)
    })
  }
  
  if (typeof props.data === 'object' && props.data !== null) {
    return Object.keys(props.data).some(key => {
      const childPath = basePath === 'root' ? `root.${key}` : `${basePath}.${key}`
      return props.matchedPaths.has(childPath) || checkChildrenMatch(props.data[key], childPath)
    })
  }
  
  return false
})

// 递归检查子节点是否匹配
const checkChildrenMatch = (obj, path) => {
  if (props.matchedPaths.has(path)) return true
  
  if (Array.isArray(obj)) {
    return obj.some((item, index) => {
      const childPath = `${path}[${index}]`
      return props.matchedPaths.has(childPath) || checkChildrenMatch(item, childPath)
    })
  }
  
  if (typeof obj === 'object' && obj !== null) {
    return Object.keys(obj).some(key => {
      const childPath = `${path}.${key}`
      return props.matchedPaths.has(childPath) || checkChildrenMatch(obj[key], childPath)
    })
  }
  
  return false
}

const valueType = computed(() => {
  if (props.data === null) return 'null'
  if (Array.isArray(props.data)) return 'array'
  if (typeof props.data === 'object') return 'object'
  return typeof props.data
})

const displayValue = computed(() => {
  if (props.data === null) return 'null'
  if (Array.isArray(props.data)) {
    return `Array(${props.data.length})`
  }
  if (typeof props.data === 'object') {
    const keys = Object.keys(props.data)
    return `Object(${keys.length})`
  }
  if (typeof props.data === 'string') {
    return props.data
  }
  return String(props.data)
})

const children = computed(() => {
  if (!hasChildren.value) return []
  
  const basePath = props.path === '' && props.keyName === null ? 'root' : currentPath.value
  
  if (Array.isArray(props.data)) {
    return props.data.map((item, index) => ({
      key: index,
      value: item,
      path: basePath
    }))
  }
  
  if (typeof props.data === 'object' && props.data !== null) {
    return Object.keys(props.data).map(key => ({
      key: key,
      value: props.data[key],
      path: basePath
    }))
  }
  
  return []
})

// 筛选后的子节点
const filteredChildren = computed(() => {
  if (!hasFilter.value) return children.value
  
  // 如果当前节点匹配，显示所有子节点（不进行过滤）
  if (isMatched.value) return children.value
  
  // 如果当前节点是匹配节点的子节点，显示所有子节点（不进行过滤）
  if (isChildOfMatched.value) return children.value
  
  // 否则，只显示匹配的子节点或其子节点匹配的子节点
  return children.value.filter(child => {
    const childPath = child.path === 'root' 
      ? (typeof child.key === 'number' ? `root[${child.key}]` : `root.${child.key}`)
      : (typeof child.key === 'number' ? `${child.path}[${child.key}]` : `${child.path}.${child.key}`)
    
    // 如果子节点匹配，显示
    if (props.matchedPaths.has(childPath)) return true
    
    // 如果子节点的子节点匹配，也显示
    return checkChildrenMatch(child.value, childPath)
  })
})

// 检查当前节点是否是匹配节点的子节点
const isChildOfMatched = computed(() => {
  if (!hasFilter.value || isMatched.value) return false
  
  // 检查当前路径是否以任何匹配路径开头（作为前缀）
  for (const matchedPath of props.matchedPaths) {
    if (matchedPath === 'root') continue
    
    // 如果当前路径以匹配路径开头，且后面跟着 . 或 [，说明是子节点
    const prefix = matchedPath + '.'
    const prefixBracket = matchedPath + '['
    if (currentPath.value.startsWith(prefix) || currentPath.value.startsWith(prefixBracket)) {
      return true
    }
  }
  
  return false
})

// 判断是否被筛选（有筛选但当前节点不匹配且没有匹配的子节点，且不是匹配节点的子节点）
const isFiltered = computed(() => {
  if (!hasFilter.value) return false
  if (isMatched.value) return false
  if (isChildOfMatched.value) return false
  return !hasMatchingChildren.value
})

const toggle = () => {
  if (hasChildren.value) {
    emit('toggle', currentPath.value)
  }
}
</script>

<style scoped>
.json-tree-node {
  font-family: 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.8;
}

.node-line {
  display: flex;
  align-items: center;
  padding: 2px 0;
  cursor: default;
  user-select: text;
}

.node-line.has-children {
  cursor: pointer;
}

.node-line.has-children:hover {
  background: #f0f0f0;
}

.expand-icon {
  display: inline-block;
  width: 16px;
  text-align: center;
  color: #666;
  font-size: 10px;
  margin-right: 4px;
}

.expand-icon i {
  font-size: 10px;
}

.expand-placeholder {
  display: inline-block;
  width: 16px;
  margin-right: 4px;
}

.node-path {
  color: #666666;
  font-size: 0.8125rem;
  margin-right: 8px;
  font-family: 'Courier New', monospace;
  opacity: 0.7;
}

.node-key {
  margin-right: 6px;
}

.key-name {
  color: #881391;
  font-weight: 500;
}

.node-value {
  color: #1a1aa6;
}

.node-value.string {
  color: #0b7500;
}

.node-value.number {
  color: #1a1aa6;
}

.node-value.boolean {
  color: #1a1aa6;
}

.node-value.null {
  color: #808080;
}

.node-value.object {
  color: #1a1aa6;
  font-style: italic;
}

.node-value.array {
  color: #1a1aa6;
  font-style: italic;
}

.node-children {
  margin-left: 20px;
  border-left: 1px solid #e0e0e0;
  padding-left: 8px;
}

/* 匹配的节点高亮样式 */
.json-tree-node.is-matched .node-line {
  background: #fff9e6;
  border-left: 3px solid #ff9800;
  padding-left: 5px;
  margin-left: -8px;
}

.json-tree-node.is-matched .key-name.matched {
  color: #ff6f00;
  font-weight: 600;
}

.json-tree-node.is-matched .node-value.matched {
  color: #ff6f00;
  font-weight: 500;
}

/* 被筛选掉的节点隐藏 */
.json-tree-node.is-filtered {
  display: none;
}
</style>
