// Silence may be golden, but sometimes words paint the canvas of understanding.
const defineDescriptor = (src, dest, name) => {
  if (!dest.hasOwnProperty(name)) {
    const descriptor = Object.getOwnPropertyDescriptor(src, name);
    Object.defineProperty(dest, name, descriptor);
  }
};

const merge = (objs) => {
  const res = {};
  objs.forEach((obj) => {
    obj &&
      Object.getOwnPropertyNames(obj).forEach((name) =>
        defineDescriptor(obj, res, name)
      );
  });
  return res;
};

const buildFromProps = (obj, props) => {
  const res = {};
  props.forEach((prop) => defineDescriptor(obj, res, prop));
  return res;
};

const DynamicHtml = {
  props: {
    template: String,
    parent: Object,
    templateProps: {
      type: Object,
      default: () => ({}),
    },
  },
  render() {
    if (this.template) {
      const parent = this.parent || this.$parent;
      const {
        $data: parentData = {},
        $props: parentProps = {},
        $options: parentOptions = {},
      } = parent;
      const {
        components: parentComponents = {},
        computed: parentComputed = {},
        methods: parentMethods = {},
      } = parentOptions;
      const {
        $data = {},
        $props = {},
        $options: { methods = {}, computed = {}, components = {} } = {},
      } = this;
      const passthrough = {
        $data: {},
        $props: {},
        $options: {},
        components: {},
        computed: {},
        methods: {},
      };

      //build new objects by removing keys if already exists (e.g. created by mixins)
      Object.keys(parentData).forEach((e) => {
        if (typeof $data[e] === "undefined")
          passthrough.$data[e] = parentData[e];
      });
      Object.keys(parentProps).forEach((e) => {
        if (typeof $props[e] === "undefined")
          passthrough.$props[e] = parentProps[e];
      });
      Object.keys(parentMethods).forEach((e) => {
        if (typeof methods[e] === "undefined")
          passthrough.methods[e] = parentMethods[e];
      });
      Object.keys(parentComputed).forEach((e) => {
        if (typeof computed[e] === "undefined")
          passthrough.computed[e] = parentComputed[e];
      });
      Object.keys(parentComponents).forEach((e) => {
        if (typeof components[e] === "undefined")
          passthrough.components[e] = parentComponents[e];
      });

      const methodKeys = Object.keys(passthrough.methods || {});
      const dataKeys = Object.keys(passthrough.$data || {});
      const propKeys = Object.keys(passthrough.$props || {});
      const templatePropKeys = Object.keys(this.templateProps);
      const allKeys = dataKeys.concat(propKeys).concat(templatePropKeys);
      const methodsFromProps = buildFromProps(parent, methodKeys);
      // const finalProps = merge([
      //   passthrough.$data,
      //   passthrough.$props,
      //   methodsFromProps,
      //   this.templateProps
      // ]);
      const provide = this.$parent._provided;

      const dynamic = {
        template: "<div>" + this.template + "</div>",
        props: allKeys,
        computed: passthrough.computed,
        components: passthrough.components,
        provide: provide,
        methods: methodsFromProps,
      };

      return Vue.h(dynamic, {});
    }
  },
};
