<script setup lang="ts">
import type { TreeProps } from 'ant-design-vue/es/tree';
import { difference, filter, flattenDeep, includes, map, pick } from 'lodash-es';
import { computed, nextTick, reactive, ref, watch } from 'vue';

import { I18nEntry, I18nRole } from '@/constants/i18n';
import { OPERATION_TYPE } from '@/enum';
import { I18N_COMMON, I18N_FORM } from '@/enum/i18n';
import { useAntdForm, useFormRules } from '@/hooks/common/form';
import { $t } from '@/locales';
import { createRole, updateRole } from '@/service/api';

defineOptions({
  name: 'OperateDrawer',
});

// 是否请求中
const loading = ref(false);
// 半勾选节点
const halfCheckedKeys = ref<string[]>([]);

// 父组件传递的值
type Props = {
  operateType: AntDesign.TableOperateType; // 操作类型
  rowData?: Api.SystemManage.RoleManage | null; // 编辑数据
  dataSource: Api.SystemManage.RoleManage[]; // 父级
  roleRouteList: Api.SystemManage.MenuManage[];
};
const props = defineProps<Props>();

// 父组件自定义事件
interface Emits {
  (e: 'submitted'): void;
}
const emit = defineEmits<Emits>();

// 抽屉显示状态
const visible = defineModel<boolean>('visible', {
  default: false,
});

const { formRef, validate, resetFields } = useAntdForm();
const { defaultRequiredRule } = useFormRules();

// 抽屉标题
const title = computed(() => I18nRole(`${props.operateType}Role`));

const model: Api.SystemManage.SaveRoleManage = reactive(createDefaultModel());

function createDefaultModel(): Api.SystemManage.SaveRoleManage {
  return {
    name: '',
    code: '',
    sort: 1,
    description: '',
    menus: [],
  };
}

// 表单校验的 key
type RuleKey = Extract<keyof Api.SystemManage.SaveRoleManage, 'name' | 'code' | 'menus' | 'sort'>;

const rules: Record<RuleKey, App.Global.FormRule> = {
  name: defaultRequiredRule,
  code: defaultRequiredRule,
  menus: { ...defaultRequiredRule, trigger: 'change' },
  sort: defaultRequiredRule,
};

// 初始化
async function handleInitModel() {
  Object.assign(model, createDefaultModel());

  if (props.operateType === OPERATION_TYPE.EDIT && props.rowData) {
    await nextTick();
    // 获取全部勾选的节点
    const checkedKeys = map(props.rowData.permissions, 'menuId');
    // 获取勾选节点的父节点
    const parentIds = map(map(props.rowData.permissions, 'menu'), 'parentId');
    // 过滤掉半勾选的节点
    const menus = filter(checkedKeys, item => !includes(parentIds, item));
    // 设置半勾选节点
    halfCheckedKeys.value = difference(checkedKeys, menus);
    Object.assign(model, {
      ...props.rowData,
      menus,
    });
  }
}

// 关闭抽屉
function closeDrawer() {
  visible.value = false;
}

// 勾选菜单权限回调
const handleMenuCheck: TreeProps['onCheck'] = (_, e) => {
  halfCheckedKeys.value = (e.halfCheckedKeys || []) as string[];
};

// 提交数据
async function handleSubmit() {
  await validate().then(async () => {
    loading.value = true;
    // 判断是否新增
    const isAdd = props.operateType === OPERATION_TYPE.ADD;
    // 获取参数
    const params = {
      id: isAdd ? undefined : model.id,
      ...pick(model, ['name', 'code', 'sort', 'description']),
      menus: flattenDeep([...model.menus, ...halfCheckedKeys.value]),
    };
    await (isAdd ? createRole : updateRole)(params)
      .then(({ error }) => {
        if (!error) {
          window.$message?.success($t(`common.${props.operateType}Success`));
          closeDrawer();
          emit('submitted');
        }
      })
      .finally(() => {
        loading.value = false;
      });
  });
}

watch(visible, () => {
  if (visible.value) {
    handleInitModel();
    resetFields();
  }
});
</script>

<template>
  <ADrawer v-model:open="visible" :title="title" :width="360">
    <AForm ref="formRef" layout="vertical" :model="model" :rules="rules">
      <AFormItem :label="I18nRole('name')" name="name">
        <AInput v-model:value="model.name" show-count :maxlength="32" :placeholder="I18nEntry(I18nRole('name'))" />
      </AFormItem>
      <AFormItem :label="I18nRole('code')" name="code">
        <AInput v-model:value="model.code" show-count :maxlength="32" :placeholder="I18nEntry(I18nRole('code'))" />
      </AFormItem>
      <AFormItem :label="$t(I18N_FORM.SORT)" name="sort" :tooltip="$t(I18N_FORM.SORT_TIP)">
        <AInputNumber
          v-model:value="model.sort"
          :min="1"
          :max="999"
          :placeholder="I18nEntry($t(I18N_FORM.SORT))"
          class="w-full"
        />
      </AFormItem>
      <AFormItem :label="I18nRole('description')" name="description">
        <ATextarea
          v-model:value="model.description"
          show-count
          :maxlength="200"
          :rows="4"
          :placeholder="I18nEntry(I18nRole('description'))"
        />
      </AFormItem>
      <AFormItem :label="I18nRole('menus')" name="menus">
        <ATree
          v-model:checkedKeys="model.menus"
          :tree-data="roleRouteList"
          :field-names="{ key: 'id' }"
          checkable
          @check="handleMenuCheck"
        />
      </AFormItem>
    </AForm>
    <template #footer>
      <ASpace :size="16">
        <AButton @click="closeDrawer">{{ $t(I18N_COMMON.CANCEL) }}</AButton>
        <AButton type="primary" :loading="loading" @click="handleSubmit">{{ $t(I18N_COMMON.CONFIRM) }}</AButton>
      </ASpace>
    </template>
  </ADrawer>
</template>
