<template>
  <div class="key-value-editor">
    <a-button class="preview-button" type="dashed" block @click="modalVisible = true">
      {{ '{ ' + objectPreview + '}' }}
    </a-button>
    <a-modal
      v-model:open="modalVisible"
      title="键值编辑"
      width="940px"
      :footer="null"
      destroy-on-close
    >
      <div class="key-value-container">
        <div
          v-for="item in localItems"
          :key="item.ukey"
          class="key-value-item"
        >
          <a-input
            v-model:value="item.key"
            placeholder="键"
            class="key-input"
            @blur="updateKey(item)"
          />
          <value-editor
            v-model:modelValue="item.value"
            @update:modelValue="updateValue"
            :forceOneLevel="forceOneLevel"
            class="value-input"
          />
          <a-popconfirm
            title="确定要删除这个项吗？"
            ok-text="确认"
            cancel-text="取消"
            @confirm="removeItem(item.key)"
          >
            <a-button type="text" danger class="item-remove">
              <DeleteOutlined />
            </a-button>
          </a-popconfirm>
        </div>
        <a-button type="dashed" block @click="addItem">
          <plus-outlined /> 添加项
        </a-button>
      </div>
      <a-button type="primary" block @click="save">
        保存
      </a-button>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
import ValueEditor from './ValueEditor.vue';
import { RandomUtils } from '@imengyu/imengyu-utils';

const props = defineProps<{
  modelValue?: Record<string, any>;
  /**
   * 这会限制用户只能创建简单的值，而不能嵌套对象或数组。
   * @default false
   */
  forceOneLevel?: boolean;
  /**
   * 默认创建的项的模板。当用户点击添加项时，会根据这个模板创建新的项。
   * @default { key: '', value: '', type: 'string' }
   */
  defaultCreateTemplate?: Omit<LocalItem, 'ukey'>;
}>();
const emit = defineEmits<{
  (e: 'update:modelValue', value: Record<string, any>): void;
}>();

type LocalItemType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null';
type LocalItem = {
  key: string;
  ukey: string;
  value: any;
  type: LocalItemType;
};

const modalVisible = ref(false);
const localItems = ref<LocalItem[]>([]);

function save() {
  const newObj = localItems.value.reduce((acc, cur) => ({
    ...acc,
    [cur.key]: cur.value,
  }), {} as Record<string, any>);
  emit('update:modelValue', newObj);
  modalVisible.value = false;
}

const objectPreview = computed(() => {
  return localItems.value.map((item) => {
    let value = '';
    if (item.type === 'object' || item.type === 'array') {
      value = '...';
    } else if (item.type === 'string') {
      value = `'${item.value}'`;
    } else if (item.type === 'null') {
      value = 'null';
    } else {
      value = item.value.toString();
    }
    return `${item.key}: ${value}`
  }).join(', ');
});

function getType(value: any): LocalItem['type'] {
  if (value === null) {
    return 'null';
  } else if (typeof value === 'string') {
    return 'string';
  } else if (typeof value === 'number') {
    return 'number';
  } else if (typeof value === 'boolean') {
    return 'boolean';
  } else if (Array.isArray(value)) {
    return 'array';
  } else if (typeof value === 'object') {
    return 'object';
  } else {
    return 'string';
  }
}

// 监听props变化
watch(
  () => props.modelValue,
  (newValue) => {
    if (newValue) {
      localItems.value = Object.entries(newValue).map(([key, value]) => ({ 
        key: key || '', 
        ukey: RandomUtils.genNonDuplicateIDHEX(10),
        value,
        type: getType(value),
      }));
    } else {
      localItems.value = [];
    }
  },
  { deep: true, immediate: true }
);

// 更新值
const updateValue = () => {
  const newObj = localItems.value.reduce((acc, cur) => ({
    ...acc,
    [cur.key]: cur.value,
  }), {} as Record<string, any>);
  emit('update:modelValue', newObj);
};

// 获取一个可用的键
const getUseableKey = (item: LocalItem) => {
  if (!item.key) {
    item.key = 'key';
  }
  
  let useableKey = item.key;
  let suffix = 1;
  
  const withoutSelfItems = localItems.value.filter((i) => i.ukey !== item.ukey);
  // 检查键是否已存在
  while (withoutSelfItems.some((item) => item.key === useableKey)) {
    useableKey = `${item.key}${suffix}`;
    suffix++;
  }
  
  return useableKey;
};

// 更新键
const updateKey = (item: LocalItem) => {
  // 检查是否有重复的key
  if (localItems.value.filter((i) => i.key === item.key).length > 1) {
    item.key = getUseableKey(item);
  }
};

// 添加项
const addItem = () => {
  const template = {
    key: `key${localItems.value.length + 1}`,
    value: '',
    ukey: RandomUtils.genNonDuplicateIDHEX(10),
    type: 'string' as LocalItemType,
    ...props.defaultCreateTemplate,
  };
  template.key = getUseableKey(template);
  localItems.value.push(template);
  updateValue();
};

// 删除项
const removeItem = (key: string) => {
  localItems.value = localItems.value.filter((item) => item.key !== key);
  updateValue();
};
</script>

<style scoped>
.key-value-editor {
  width: 100%;
}
.preview-button {
  max-width: 400px;
}
.key-value-container {
  width: 100%;
  max-height: 500px;
  margin-bottom: 12px;
  overflow-y: auto;
}

.key-value-item {
  display: flex;
  align-items: flex-start;
  margin-bottom: 8px;
}

.key-input {
  width: 120px;
  margin-right: 8px;
}

.value-input {
  flex: 1;
  margin-right: 8px;
}
</style>