<script setup lang="ts">
import type { CSSProperties, VNode } from 'vue';
import { getCurrentInstance, ref, useSlots, watch } from 'vue';
import type { FieldChange, FormConfig } from './types';
import UForm from './UForm.vue';

const props = withDefaults(
  defineProps<{
    // drawer
    visible: boolean;
    title?: string;
    placement?: 'top' | 'right' | 'left' | 'bottom';
    width?: string | number;
    height?: string | number;
    extra?: VNode;
    push?: boolean | { distance: string | number };
    cancelText?: string;
    closable?: boolean;
    closeIcon?: VNode;
    confirmLoading?: boolean;
    bodyStyle?: CSSProperties;
    mask?: boolean;
    maskClosable?: boolean;
    destroyOnClose?: boolean;
    getContainer?: (instance: any) => HTMLElement;
    footer?: string | null;
    okText?: string;
    okType?: string;
    zIndex?: number;
    footerStyle?: any;
    // form
    value: Record<string, any>;
    config: FormConfig[];
    size?: 'large' | 'small' | 'default';
    labelCol?: {
      span?: number;
      offset?: number;
    };
    // 预览模式
    preview?: boolean;
    layout?: 'horizontal' | 'vertical' | 'inline';
    rules?: object;
    formClass?: string;
  }>(),
  {
    // drawer
    visible: false,
    title: '对话框',
    width: 378,
    height: 378,
    placement: 'right',
    closable: true,
    destroyOnClose: false,
    mask: true,
    maskClosable: true,
    getContainer: () => document.body,
    zIndex: 1000,
    footerStyle: { textAlign: 'right' },
    okText: '确定',
    cancelText: '取消',
    okType: 'primary',
    // form
    config: () => [],
    size: 'default',
    layout: 'horizontal',
    value: () => ({})
  }
);
const slots = useSlots();
const ctx = getCurrentInstance();

const visible = ref(props.visible);
const title = ref(props.title);

const handleOk = (e: Event) => {
  validator().then(() => {
    ctx?.emit('ok', e);
  });
};

const handleCancel = (e: Event) => {
  resetFields();
  visible.value = false;
  ctx?.emit('cancel', e);
};

const formRef = ref();
const value = ref(props.value);
const config = ref(props.config);

const validator = (args?: any) => {
  return formRef.value?.validate(args);
};

const resetFields = (args?: any) => {
  return formRef.value?.resetFields(args);
};

const onSubmit = (e: any) => {
  ctx?.emit('submit', e);
};
const onReset = (e: any) => {
  ctx?.emit('reset', e);
};

const onFieldChange = (val: FieldChange) => {
  ctx?.emit(`${val.field}Change`, val);
  ctx?.emit('fieldChange', val);
  ctx?.emit('update:value', val.fields);
};

watch(
  () => props.value,
  () => {
    value.value = props.value;
  },
  {
    deep: true
  }
);
watch(
  () => props.config,
  () => {
    config.value = props.config;
  },
  {
    deep: true
  }
);
watch(
  () => props.visible,
  () => {
    visible.value = props.visible;
  }
);
// 处理点击遮罩触发关闭时，同步更新
watch(
  () => visible.value,
  () => {
    ctx?.emit('update:visible', visible.value);
  }
);
watch(
  () => props.title,
  () => {
    title.value = props.title;
  }
);
defineExpose({
  formRef,
  validate: validator,
  resetFields
});
</script>

<template>
  <a-drawer
    v-model:open="visible"
    :title="title"
    :placement="placement"
    :push="push"
    :extra="extra"
    :width="width"
    :cancel-text="cancelText"
    :closable="closable"
    :mask="mask"
    :body-style="bodyStyle"
    :footer="footer"
    :get-container="getContainer"
    :mask-closable="maskClosable"
    :confirm-loading="confirmLoading"
    :destroy-on-close="destroyOnClose"
    :footer-style="footerStyle"
    :ok-text="okText"
    :ok-type="okType"
    class="u-drawer-form"
  >
    <template v-if="title" #title>
      <slot name="title" />
    </template>
    <UForm
      ref="formRef"
      v-model:value="value"
      :config="config"
      :size="size"
      :layout="layout"
      :rules="rules"
      :label-col="labelCol"
      :class="formClass"
      :preview="preview"
      @submit="onSubmit"
      @reset="onReset"
      @field-change="onFieldChange"
    >
      <template v-for="(item, key) in slots" :key="key" #[key]="{ data, validate, reset }">
        <slot :name="key" :data="data" :validate="validate" :reset="reset" />
      </template>
    </UForm>
    <template v-if="footer !== null" #footer>
      <template v-if="Object.keys(slots).includes('footer')">
        <slot name="footer" :data="value" :validate="validator" :reset="resetFields" />
      </template>
      <template v-else>
        <a-button @click="handleCancel">
          {{ cancelText }}
        </a-button>
        <a-button type="primary" :loading="confirmLoading" @click="handleOk">
          {{ okText }}
        </a-button>
      </template>
    </template>
    <template #extra>
      <slot name="extra" :data="value" :validate="validator" :reset="resetFields" />
    </template>
  </a-drawer>
</template>

<style>
.u-drawer-form .ant-drawer-footer .ant-btn+.ant-btn:not(.ant-dropdown-trigger){margin-left:8px}
</style>
