<template>
  <Form
    ref="formRef"
    v-bind="formProps"
    :model="formModel"
    :rules="formRules"
  >
    <DynamicFormCate
      v-if="formModel"
      :formModel="formModel"
      :formDefine="formDefine"
      :formDefineParentKey="''"
      :formDefineParentLabel="''"
    />
  </Form>
</template>

<script setup lang="ts">
import { computed, onMounted, provide, reactive, ref, toRef, watch, type PropType } from 'vue';
import { waitTimeOut } from '@imengyu/imengyu-utils';
import DynamicFormCate from './DynamicFormCate.vue';
import Form, { type FormProps } from '../form/Form.vue';
import type { FormDefine, FormDefineItem, FormExport } from '.';
import type { Rules } from 'async-validator';

const props = defineProps({	
  formDefine: {
    type: Object as PropType<FormDefine>,
    default: () => ({})
  },
  formProps: {
    type: Object as PropType<Omit<FormProps, 'model' | 'rules'>>,
    default: () => ({}) 
  },
  formGlobalParams: {
    type: Object,
    default: () => ({})
  },
});

const formRef = ref<any>();
const formModel = ref<any>(null);
const formRules = computed(() => {
  const rules: Rules = {};
  function loop(prevKey: string, arr: FormDefineItem[]) {
    if (!arr || !(arr instanceof Array))
     return;
    for (const item of arr) {
      const key = prevKey ? `${prevKey}.${item.name}` : item.name;
      if (key && item.rules) 
        rules[key] = item.rules;
      if (item.children) {
        loop(
          item.children.propNestType === 'flat' ? key : prevKey, 
          item.children.items
        );
      }
    }
  }
  loop('', props.formDefine.items);
  return rules;
});
const formGlobalParams = toRef(props.formGlobalParams);

provide('formTopModel', formModel);
provide('formGlobalParams', formGlobalParams);

watch(() => props.formDefine, (v) => {
  reloadFormData();
});

let isErrorState = false;
let initCb : () => any = () => {
  return {};
};

function initFormData(data: () => any) {
  initCb = data;
}
function loadFormData(value?: Record<string, any>) {
  const obj = reactive(initCb());

  function loop(prevKey: string, arr: FormDefineItem[]) {
    if (!arr || !(arr instanceof Array))
     return;
    for (let index = 0; index < arr.length; index++) {
      const item = arr[index];
      const key = prevKey ? `${prevKey}.${item.name}` : item.name;
      if (key) {
        const valueProvided = value?.[key] ;
        obj[key] = valueProvided == null || valueProvided == undefined ? 
          (typeof item.defaultValue === 'function' ? item.defaultValue() : item.defaultValue)  
          : valueProvided ?? null;
        item.fullName = key;
      } else {
        item.fullName = '';
      }
      if (item.children)
        loop(
          item.children.propNestType === 'flat' ? key : prevKey, 
          item.children.items
        );
    }
  }

  loop('', props.formDefine.items);
  formModel.value = obj;
}
async function submitForm<T = Record<string, any>>() : Promise<T|null> {
  await formRef.value.clearValidate();
  await waitTimeOut(50);
  
  try {
    await formRef.value.validate();
  } catch (e) {
    if (isErrorState)
      uni.showToast({
        title: '表单中有未填写项，请检查',
        icon: 'none'
      });
    console.log(e);
    isErrorState = true;
    return null;
  }
  isErrorState = false;
  return formModel.value;
}
function resetForm() {
  loadFormData();
}

function reloadFormData() {
  if (!formModel.value)
    loadFormData();
}

onMounted(() => {
  setTimeout(() => reloadFormData(), 300);
});

defineExpose<FormExport>({
  getFormRef: () => formRef.value,
  getFormData: () => formModel.value,
  initFormData,
  loadFormData,
  submitForm,
  resetForm,
})

</script>