import Color from "./components/color.vue";
import Select from "./components/select.vue";
import Num from "./components/num.vue";
import Checkbox from "./components/checkbox.vue";
import Proportion from "./components/proportion.vue";
import originDescribes from "./describes.json";
import { Ref } from "vue";

export const colorType = "color";
export const selectType = "select";
export const numType = "num";
export const checkType = "check";
export const proportionType = "proportion";

export const propertyComponents = {
  [colorType]: Color,
  [numType]: Num,
  [selectType]: Select,
  [checkType]: Checkbox,
  [proportionType]: Proportion,
};

export type PropertyType = keyof typeof propertyComponents;
export type PropertyComponents<T extends PropertyType> =
  (typeof propertyComponents)[T];

export type PropertyProps<T extends PropertyType> = InstanceType<
  PropertyComponents<T>
>["$props"];
export type PropertyValue<T extends PropertyType> = PropertyProps<T>["value"];

export type PropertyDescribes = Record<
  string,
  {
    type: PropertyType;
    label: string;
    default?: PropertyValue<PropertyType>;
    props?: Partial<PropertyProps<PropertyType>>;
    value?: PropertyValue<PropertyType>;
  }
>;
export type PropertysData<T extends PropertyDescribes = PropertyDescribes> = {
  [K in keyof T]: PropertyValue<T[K]["type"]>;
};

export type PropertyKey = keyof typeof originDescribes;
export type PropertyKeys = PropertyKey[];

export const mergeDescribes = (data: Ref<any>, defData: any, keys: PropertyKeys) => {
  const describes: PropertyDescribes = {};
  for (const key of keys) {
    if (!originDescribes[key]) {
      continue;
    }
    ;(describes as any)[key] = { ...originDescribes[key] };

    if (!("value" in describes[key])) {
      Object.defineProperty(describes[key], "value", {
        get() {
          return key in data.value
            ? data.value[key]
            : key in defData
            ? defData[key]
            : describes[key].default;
        },
        set(val) {
          data.value[key] = val;
          return true;
        },
      });
    }
  }
  return describes;
};

export { default as PropertyUpdate } from "./mount.vue";
export { default as Operate } from "./hover-operate.vue";
