import { defineComponent, h, markRaw } from 'vue';
import {
  buildInSetters,
  ISetter,
  SetterValueTypes,
  isJSExpression,
  isJSFunction
} from '@vtj/engine';
import SetterView from '../views/SetterView.vue';

export default defineComponent({
  name: 'SetterRenderer',
  props: {
    name: String,
    label: String,
    title: String,
    value: {
      type: [String, Object, Array, Number, Boolean],
      default: ''
    },
    setters: {
      type: [String, Object, Array],
      required: true,
      default() {
        return [];
      }
    },
    options: {
      type: Array,
      default() {
        return [];
      }
    },
    variable: {
      type: Boolean,
      default: true
    },
    node: Object,
    // 默认绑定属性，如果设置为false，需要手动侦听change事件做相应处理
    binding: {
      type: Boolean,
      default: true
    }
  },
  computed: {
    computedSetters() {
      const setters = Array.isArray(this.setters)
        ? this.setters
        : [this.setters];
      return setters.map((setter) => {
        let component;
        if (typeof setter === 'string') {
          //@ts-ignore
          component = this.getComopnent(setter);
          return {
            component: markRaw(component),
            name: setter,
            label: setter,
            props: {}
          };
        } else {
          const item: ISetter = setter as ISetter;
          //@ts-ignore
          component = item.component || this.getComopnent(item.name);
          return {
            component: markRaw(component),
            name: item.name,
            label: item.label || item.name,
            props: item.props
          };
        }
      });
    },
    computedOptions() {
      const options = this.options || [];
      return options.map((option) => {
        if (typeof option === 'string') {
          return {
            label: option,
            value: option
          };
        }
        return option;
      });
    },
    defaultSetter() {
      const { value, computedSetters } = this;
      let type: string = typeof value;
      if (type === 'object') {
        if (Array.isArray(value)) {
          type = 'array';
        } else if (isJSExpression(value)) {
          type = 'JSExpression';
        } else if (isJSFunction(value)) {
          type = 'JSFunction';
        }
      }
      const setters = SetterValueTypes[type] || [];
      if (setters.length) {
        return computedSetters.find((setter) => setters.includes(setter.name))
          ?.name;
      }
      return computedSetters[0].name;
    }
  },
  render() {
    const {
      name,
      label,
      title,
      value,
      computedSetters,
      computedOptions,
      variable,
      changeValue,
      defaultSetter,
      node
    } = this;
    return h(SetterView, {
      node,
      name,
      label,
      title,
      setters: computedSetters,
      defaultSetter: defaultSetter,
      variable,
      value,
      options: computedOptions,
      onChange: changeValue
    } as any);
  },
  emits: ['change'],
  methods: {
    getComopnent(name: any) {
      return typeof name === 'string'
        ? buildInSetters[name] || buildInSetters.InputSetter
        : name;
    },
    changeValue(val: any) {
      const { name, node, binding } = this;
      if (binding && node && name) {
        if (['ref', 'key', 'className', 'children'].includes(name)) {
          node.update({
            [name]: val
          });
        } else {
          node.setPropValue(name, val);
        }
      }
      this.$emit('change', val);
    }
  }
});
