<script setup lang="ts">
import { computed, watch } from 'vue';
import type { LabelPlacement } from 'naive-ui/es/form/src/interface';
import { $t } from '@/locales';
import { type ModelCallback, useNaiveForm } from '@/hooks/common/form';

defineOptions({
  name: 'OperateModel'
});

interface Props {
  operateType?: NaiveUI.TableOperateType;
  rowData?: object | null;
  rules?: Record<string, App.Global.FormRule | App.Global.FormRule[]>;
  title?: string;
  modelTitle?: string;
  classStyle?: string;
  scrollbarClass?: string;
  labelPlacement?: LabelPlacement;
  labelWidth?: string;
}

type Model = Record<string, any>;

const props = withDefaults(defineProps<Props>(), {
  operateType: 'add',
  rowData: null,
  classStyle: 'w-800px',
  rules: () => ({}),
  title: '',
  modelTitle: '',
  scrollbarClass: 'pr-20px',
  labelPlacement: 'left',
  labelWidth: '100px'
});

const visible = defineModel<boolean>('visible', { default: false });
const model = defineModel<Model | undefined>('model', { required: true });
const initModel: Model | undefined = JSON.parse(JSON.stringify(model.value));

const { formRef, validate } = useNaiveForm();

const title = computed(() => {
  if (props.modelTitle) return props.modelTitle;
  const titles: Record<NaiveUI.TableOperateType, string> = {
    add: '添加',
    edit: '修改'
  };
  return titles[props.operateType] + props.title;
});

const emit = defineEmits<{
  // 提交前的参数处理
  (e: 'preSubmit', callback: (options: { data?: Model; flag?: boolean }) => void): void;
  // 提交表单
  (e: 'submit', callback: (params: ModelCallback<Model>) => void): void;
  // 打开弹窗时，传递数据和类型，便于子组件操作
  (e: 'open', type: NaiveUI.TableOperateType, model: Model): void;
}>();

watch(visible, val => {
  if (val) {
    // 在打开时
    if (props.operateType === 'add') {
      model.value = JSON.parse(JSON.stringify(initModel));
      emit('open', 'add', model.value as Model);
    } else if (props.operateType === 'edit') {
      // 如果外面不传递rowData，就直接是Model了
      // 请在数据回来时，再打开弹窗
      if (props.rowData) model.value = props.rowData;
      emit('open', 'edit', model.value as Model);
    }
  }
});

function closeDrawer() {
  visible.value = false;
}

// 父组件调用的传递
// async function handleSubmit(callback) {
//   callback({ add: addAbility, edit: editAbility, getData });
// }
async function handleSubmit() {
  await validate();

  let next = true;
  emit('preSubmit', ({ data, flag = true }) => {
    if (!flag || !data) {
      next = false;
      return;
    }
    model.value = data;
  });
  if (!next) return;

  try {
    emit('submit', async ({ add, edit, getData, transformData = null }) => {
      const isAdd = props.operateType === 'add';
      const data = (
        transformData !== null ? transformData(JSON.parse(JSON.stringify(model.value))) : model.value
      ) as Model;
      const { error } = isAdd ? add && (await add(data)) : edit && (await edit(data));
      if (!error) {
        if (!props.modelTitle) window.$message?.success($t(isAdd ? 'common.addSuccess' : 'common.updateSuccess'));
        else window.$message?.success(`${props.modelTitle}成功`);
        closeDrawer();
        await getData?.();
      }
    });
  } catch (e) {
    window.$message?.error(`操作失败${e}`);
  }
}
</script>

<template>
  <NModal v-model:show="visible" :title="title" :mask-closable="false" preset="card" :class="classStyle">
    <NScrollbar :class="scrollbarClass">
      <NForm
        ref="formRef"
        :model="model"
        :rules="rules"
        :label-placement="labelPlacement"
        require-mark-placement="left"
        :label-width="labelWidth"
      >
        <NGrid responsive="screen" item-responsive>
          <slot name="formItem" />
        </NGrid>
      </NForm>
    </NScrollbar>
    <template #footer>
      <NSpace justify="end" :size="16">
        <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
        <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
      </NSpace>
    </template>
  </NModal>
</template>

<style scoped></style>
