<template>
  <div class="json-tree-node">
    <div
      class="node-line"
      :class="{ 'has-children': hasChildren, 'is-expanded': isExpanded }"
      @click="toggle"
    >
      <span v-if="hasChildren" class="expand-icon">
        {{ isExpanded ? '▼' : '▶' }}
      </span>
      <span v-else class="expand-placeholder"></span>
      <span class="node-key" v-if="key !== null">
        <span class="key-name">{{ key }}</span>:
      </span>
      <span class="node-value" :class="valueType">
        <span v-if="valueType === 'string'">"{{ displayValue }}"</span>
        <span v-else>{{ displayValue }}</span>
      </span>
    </div>
    <div v-if="hasChildren && isExpanded" class="node-children">
      <JsonTreeNode
        v-for="(child, index) in children"
        :key="index"
        :data="child.value"
        :key-name="child.key"
        :path="child.path"
        :expanded="expanded"
        @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
  }
})

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)
})

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 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-placeholder {
  display: inline-block;
  width: 16px;
  margin-right: 4px;
}

.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;
}
</style>
