import type { IFormItem, ChildrenFn } from "./type";
import type { FormInstance } from "ant-design-vue";
import { ref, computed, watch, defineComponent } from "vue";
import { Form, Collapse, CollapsePanel } from "ant-design-vue";
import CusFormItem from "./CusFormItem.vue";
import { pick, get } from "lodash-es";

export default defineComponent({
  name: "DCusForm",
  props: {
    columns: {
      type: Array as () => IFormItem[],
      default: () => [],
    },
    formModel: {
      type: Object as () => Record<string, any>,
      default: () => ({}),
    },
  },
  emits: ["change"],
  setup(props, { emit }) {
    const formModel = ref<Record<string, any>>({});
    const formRef = ref<FormInstance>();
    // 记录被格式化的数据
    const formatFormModel = ref<Record<string, any>>({});

    const formItems = computed(() => {
      return props.columns.map((item) => {
        return {
          ...item,
          rules: item?.rules || [],
        };
      });
    });

    const setFormModel = (columns: IFormItem[]) => {
      columns?.forEach((item) => {
        // 设置表单初始值
        if (item.type === "group") {
          setFormModel(item.children as IFormItem[]);
        } else if (item.type === "dependency") {
          const list = (item.children as ChildrenFn)?.(
            pick(formModel.value, item.name || []),
            formModel
          );
          setFormModel(list);
        } else {
          if (item.type === "divider") return;
          // 获取初始值 先从formModel中取，没有则取默认值
          const value = get(props.formModel, item.prop);
          // 表单的值需要转换成把option值转换成表单值
          formModel.value[item.prop] = item?.valueToForm
            ? item.valueToForm(value, props.formModel)
            : value ?? item.defaultValue;
          if (item.format) {
            item.format(formatFormModel, formModel.value[item.prop]);
          } else {
            formatFormModel.value[item.prop] = value ?? item.defaultValue;
          }
        }
      });
    };

    /* 处理修改值 */
    const handleValueChange = (val: unknown, child: IFormItem) => {
      formModel.value[child.prop] = val;
      // 根据传入转换方法，格式化数据
      if (child.format) {
        child.format(formatFormModel, val);
      } else {
        formatFormModel.value[child.prop] = val;
      }
      emit("change", formatFormModel.value);
    };

    /* 单个表单项 */
    const getItem = (child: IFormItem) => {
      switch (child.type) {
        case "dependency": {
          const list = (child.children as ChildrenFn)?.(
            pick(formModel.value, child.name || []),
            formModel
          );
          setFormModel(list);
          return getFormItems(list);
        }
        case "group": {
          return getGroupItem(child);
        }
        default: {
          return (
            <CusFormItem
              key={child.prop}
              item={child}
              modelValue={formModel.value[child.prop]}
              onUpdate:modelValue={(val: any) => {
                handleValueChange(val, child);
              }}
            />
          );
        }
      }
    };
    /* 分组 */
    const getGroupItem = (item: IFormItem) => {
      return (
        <Collapse style={{ borderRadius: 0}}>
          <CollapsePanel style={{ borderRadius: 0}} key={item.prop} header={item.label}>
            {(item.children as IFormItem[])?.map((child) => {
              return getItem(child);
            })}
          </CollapsePanel>
        </Collapse>
      );
    };

    /* 获取表单项 */
    const getFormItems = (formItemList: IFormItem[]): any => {
      return formItemList.map((item) => {
        switch (item.type) {
          case "group":
            return getGroupItem(item);
          default:
            return getItem(item);
        }
      });
    };

    watch(
      () => formItems.value,
      (val) => {
        if (val) setFormModel(val);
      },
      { immediate: true }
    );

    return () => (
      <Form
        model={formModel}
        colon={false}
        label-col={{ span: 8 }}
        ref={formRef}
        layout="horizontal"
        size="small"
      >
        {getFormItems(formItems.value)}
      </Form>
    );
  },
});
