<script generic="T extends object" lang="ts" setup>
import ADialog from '@/components/a-dialog/ADialog.vue'
import Utils from '@/common/utils'
import type { Arrayable } from 'element-plus/es/utils'
import {
  ElMessage,
  type FormInstance,
  type FormItemRule,
} from 'element-plus'
import FormUtil from '@/common/utils/formUtil.ts'

const props = withDefaults(
  defineProps<{
    title: string
    detailsLoader: (id?: string) => Promise<T | undefined | null | void>
    doSubmit: (data: T) => Promise<boolean | void>
    rules?: Partial<Record<string, Arrayable<FormItemRule>>>
    labelWidth?: string
  }>(),
  {
    rules: () => ({} as Partial<Record<string, Arrayable<FormItemRule>>>),
    labelWidth: '80px',
  })

const formIns = useTemplateRef<FormInstance>('formRef')
const showDialog = ref(false)
const loading = ref(false)

const formData = Utils.resetAble(reactive<T>({} as T))

function dialogCloseHandler() {
  formData.$reset()
}

function submitHandler() {
  return FormUtil.submit(formIns, () => props.doSubmit(formData.$clone() as T))
    .then(res => {
      ElMessage.success('提交成功')
      if ((res ?? true)) {
        showDialog.value = false
      }
    })
}

defineExpose({
  open(id?: string) {
    loading.value = true
    props.detailsLoader(id)
      .then(res => {
        formData.$reset((res ?? {}) as any)
      })
      .finally(() => {
        loading.value = false
      })
    showDialog.value = true
  },
})
</script>

<template>
  <ADialog
    v-model:show="showDialog"
    :closed="dialogCloseHandler"
    :submit-handler="submitHandler"
    :title="title"
  >
    <ElForm
      ref="formRef"
      v-loading="loading"
      :label-width="labelWidth" :model="formData"
      :rules="rules"
      class="form-panel">
      <slot :formData="formData as T"/>
    </ElForm>
  </ADialog>
</template>

<style lang="stylus">
.form-panel > div:first-child {
  padding 20px
  display: grid;
  gap: 0 30px;
}
</style>
