<template>
  <ElFormItem class="vtj-setter" size="small" label-positon="left">
    <template #label>
      <ElTooltip
        v-if="props.title"
        placement="top-start"
        :content="props.title">
        {{ props.label || props.name }}
      </ElTooltip>
      <span v-else>{{ props.label || props.name }}</span>
    </template>
    <div class="vtj-setter__content">
      <div v-if="currentSetter" class="vtj-setter__input">
        <component
          :is="currentSetter.component"
          v-bind="currentSetter.props"
          :options="props.options"
          v-model="modelValue"
          @change="onChange"
          :disabled="isBinding"></component>
      </div>
      <div class="vtj-setter__action">
        <i
          v-if="props.variable"
          @click="openBinder"
          class="vtj-icon-vars"
          :class="{ 'is-active': isBinding }"
          title="绑定变量"></i>
        <ElDropdown
          v-if="props.setters.length > 1"
          size="small"
          popper-class="vtj-setter-switch"
          @command="changeSetter">
          <i class="vtj-icon-switch" title="切换设置器"></i>
          <template #dropdown>
            <ElDropdownMenu>
              <ElDropdownItem
                v-for="item in props.setters"
                :command="item"
                :key="item.name">
                <i
                  v-if="item.name == currentSetter.name"
                  class="vtj-icon-check"></i>
                <i v-else class="vtj-icon-placeholder"></i>
                {{ item.label }}
              </ElDropdownItem>
            </ElDropdownMenu>
          </template>
        </ElDropdown>
      </div>
    </div>
    <VariableBinder
      v-if="binderVisible"
      v-model="binderVisible"
      :value="binderValue"
      :node="props.node"
      @submit="onVarsSubmit"
      @cancel="closeBinder"
      @remove="onVarsRemove"></VariableBinder>
  </ElFormItem>
</template>
<script lang="ts" setup>
import VariableBinder from '../binders/VariableBinder.vue';
import {
  ElFormItem,
  ElTooltip,
  ElDropdown,
  ElDropdownMenu,
  ElDropdownItem
} from 'element-plus';
import { ref, watch, computed } from 'vue';

import { ISetter, INode, isJSExpression } from '@vtj/engine';

export interface Props {
  node: INode;
  name: string;
  label?: string;
  title?: string;
  setters: ISetter[];
  variable?: boolean;
  value?: any;
  options?: any[];
  defaultSetter?: string;
}

const props = withDefaults(defineProps<Props>(), {
  label: '',
  options: () => [],
  variable: true
});

const emit = defineEmits(['change']);

const binderVisible = ref(false);
const binderValue = ref();

const currentSetter = ref(
  props.setters.find((n) => n.name === props.defaultSetter) || props.setters[0]
);

const modelValue = ref(props.value);

const isBinding = computed(() => {
  return !!isJSExpression(modelValue.value);
});

const setterValueRecored = {
  [currentSetter.value.name]: modelValue.value
};

const changeSetter = (setter: ISetter) => {
  setterValueRecored[currentSetter.value.name] = modelValue.value;
  currentSetter.value = setter;
  modelValue.value = setterValueRecored[setter.name] ?? undefined;
  onChange(modelValue.value);
};

watch(
  () => props.value,
  () => {
    modelValue.value = props.value;
  }
);
watch(
  () => props.defaultSetter,
  () => {
    currentSetter.value =
      props.setters.find((n) => n.name === props.defaultSetter) ||
      props.setters[0];
  }
);

const onChange = (value: any) => {
  emit('change', value);
};

const openBinder = () => {
  binderVisible.value = true;
  binderValue.value = isJSExpression(modelValue.value)
    ? modelValue.value
    : {
        type: 'JSExpression',
        value: ''
      };
};

const closeBinder = () => {
  binderVisible.value = false;
  binderValue.value = null;
};

const onVarsSubmit = (value: any) => {
  setterValueRecored[currentSetter.value.name] = modelValue.value;
  modelValue.value = value;
  emit('change', value);
  closeBinder();
};

const onVarsRemove = () => {
  closeBinder();
  modelValue.value = setterValueRecored[currentSetter.value.name] ?? undefined;
  emit('change', '');
};
</script>
