<template>
  <div class="json-editor" :style="{ height: height + 'px' }">
    <textarea
      ref="textareaRef"
      v-model="editorValue"
      :readonly="readonly"
      class="json-textarea"
      @input="handleInput"
      @blur="validateJson"
    ></textarea>
    <div v-if="error" class="error-message">
      {{ error }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'

// 定义props
interface Props {
  modelValue?: any
  value?: any
  height?: number
  readonly?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  height: 300,
  readonly: false
})

// 定义emit
const emit = defineEmits(['update:modelValue', 'input', 'change'])

// 内部状态
const textareaRef = ref<HTMLTextAreaElement>()
const editorValue = ref('')
const error = ref('')

// 将值转换为JSON字符串
const formatJsonValue = (value: any): string => {
  try {
    return JSON.stringify(value, null, 2) || ''
  } catch {
    return ''
  }
}

// 从JSON字符串解析值
const parseJsonValue = (str: string): any => {
  if (!str.trim()) return null
  try {
    return JSON.parse(str)
  } catch (e) {
    throw new Error('Invalid JSON')
  }
}

// 初始化值
const initializeValue = () => {
  const val = props.modelValue !== undefined ? props.modelValue : props.value
  editorValue.value = formatJsonValue(val)
}

// 处理输入变化
const handleInput = () => {
  try {
    const parsedValue = parseJsonValue(editorValue.value)
    error.value = ''
    emit('update:modelValue', parsedValue)
    emit('input', parsedValue)
    emit('change', parsedValue)
  } catch (e) {
    error.value = (e as Error).message
  }
}

// 验证JSON
const validateJson = () => {
  if (!editorValue.value.trim()) {
    error.value = ''
    return
  }
  try {
    JSON.parse(editorValue.value)
    error.value = ''
  } catch (e) {
    error.value = 'Invalid JSON format'
  }
}

// 监听外部值的变化
watch(() => props.modelValue, (newVal) => {
  const formatted = formatJsonValue(newVal)
  if (formatted !== editorValue.value) {
    editorValue.value = formatted
  }
})

// 初始化
initializeValue()
</script>

<style scoped>
.json-editor {
  position: relative;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden;
}

.json-textarea {
  width: 100%;
  height: 100%;
  padding: 10px;
  border: none;
  outline: none;
  resize: none;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 13px;
  line-height: 1.5;
  box-sizing: border-box;
  background-color: #fafafa;
}

.json-textarea:read-only {
  background-color: #f5f5f5;
  cursor: not-allowed;
}

.error-message {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 5px 10px;
  background-color: #fef0f0;
  color: #f56c6c;
  font-size: 12px;
  border-top: 1px solid #f56c6c;
}
</style>
</template>
</file_path>