<script setup lang="ts">
import { detailBaseEmployeeApi, modifyPermissionApi, pagePermissionApi, type BaseEmployeeResultVO, type NdmPermissionResultVO, type NdmPermissionSaveVO, type Station } from '@/apis';
import { PERMISSION_TYPE_LITERALS, PERMISSION_TYPE_NAMES, type PermissionType } from '@/enums';
import { useStationStore } from '@/stores';
import { parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { objectEntries } from '@vueuse/core';
import { isCancel } from 'axios';
import { cloneDeep } from 'es-toolkit';
import { NButton, NCheckbox, NDataTable, NFlex, NModal, NText, type DataTableColumn, type DataTableColumns } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, h, ref, toRefs } from 'vue';

type NdmPermissionSaveOrResultVO = NdmPermissionSaveVO | NdmPermissionResultVO;

const props = defineProps<{
  employeeId?: string;
}>();

const stationStore = useStationStore();
const { stations } = storeToRefs(stationStore);

const show = defineModel<boolean>('show', { default: false });

const { employeeId } = toRefs(props);

const abortController = ref<AbortController>(new AbortController());

const employee = ref<BaseEmployeeResultVO>();
const { mutateAsync: getEmployeeAsync } = useMutation({
  mutationFn: async () => {
    abortController.value.abort();
    abortController.value = new AbortController();

    if (!employeeId.value) return;

    const signal = abortController.value.signal;

    const data = await detailBaseEmployeeApi(employeeId.value, { signal });
    return data;
  },
  onSuccess: (data) => {
    if (!data) return;
    employee.value = data;
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

// 从后端获取的原始权限列表
const originalList = ref<NdmPermissionResultVO[]>([]);
// 当前用户配置的权限列表
const currentList = ref<NdmPermissionSaveOrResultVO[]>([]);

const { mutate: getPermissions, isPending: permissionsLoading } = useMutation({
  mutationFn: async () => {
    if (!employeeId.value) throw new Error('员工ID不能为空');

    abortController.value.abort();
    abortController.value = new AbortController();

    const signal = abortController.value.signal;

    const data = await pagePermissionApi(
      {
        model: {
          employeeId: employeeId.value,
        },
        current: 1,
        size: Object.keys(PERMISSION_TYPE_LITERALS).length * stations.value.length,
      },
      { signal },
    );

    return data;
  },
  onSuccess: (data) => {
    if (!data) return;
    const { records } = data;
    originalList.value = cloneDeep(records);
    currentList.value = cloneDeep(records);
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const onUpdatePermissionChecked = (checked: boolean, stationCode: Station['code'], permissionType: PermissionType) => {
  if (!employeeId.value) return;
  if (checked) {
    const existed = currentList.value.some((permission) => permission.stationCode === stationCode && permission.type === permissionType);
    if (!existed) {
      const saveVO: NdmPermissionSaveVO = {
        employeeId: employeeId.value,
        stationCode,
        type: permissionType,
      };
      currentList.value.push(saveVO);
    }
  } else {
    const index = currentList.value.findIndex((permission) => permission.stationCode === stationCode && permission.type === permissionType);
    if (index !== -1) {
      currentList.value.splice(index, 1);
    }
  }
};

const tableColumns = computed<DataTableColumns<Station>>(() => {
  return [
    {
      title: () => {
        const permissionCount = currentList.value.length;
        const permissionTypeCount = objectEntries(PERMISSION_TYPE_LITERALS).length;
        const checked = permissionCount === stations.value.length * permissionTypeCount;
        const indeterminate = permissionCount > 0 && permissionCount < stations.value.length * permissionTypeCount;
        return h(NCheckbox, {
          checked,
          indeterminate,
          onUpdateChecked: (checked) => {
            objectEntries(PERMISSION_TYPE_LITERALS).forEach(([permissionType]) => {
              stations.value.forEach((station) => {
                onUpdatePermissionChecked(checked, station.code, permissionType);
              });
            });
          },
        });
      },
      key: 'row-check',
      align: 'center',
      width: 60,
      fixed: 'left',
      render: (rowData) => {
        const { code: stationCode } = rowData;
        const permissionTypeCount = objectEntries(PERMISSION_TYPE_LITERALS).length;
        const stationCheckedPermissions = currentList.value.filter((permission) => permission.stationCode === stationCode);
        const checked = stationCheckedPermissions.length === permissionTypeCount;
        const indeterminate = stationCheckedPermissions.length > 0 && stationCheckedPermissions.length < permissionTypeCount;
        return h(NCheckbox, {
          checked,
          indeterminate,
          onUpdateChecked: (checked) => {
            objectEntries(PERMISSION_TYPE_LITERALS).forEach(([permissionType]) => {
              onUpdatePermissionChecked(checked, stationCode, permissionType);
            });
          },
        });
      },
    },
    { title: '车站编号', key: 'code', align: 'center', width: 120 },
    { title: '车站名称', key: 'name', align: 'center', width: 360 },
    // 「权限」列
    ...objectEntries(PERMISSION_TYPE_NAMES).map<DataTableColumn<Station>>(([permissionType, title]) => ({
      title: () => {
        const permissionCount = currentList.value.filter((permission) => permission.type === permissionType).length;
        const checked = permissionCount === stations.value.length;
        const indeterminate = permissionCount > 0 && permissionCount < stations.value.length;
        return h(
          NFlex,
          {
            justify: 'center',
            align: 'center',
          },
          {
            default: () => [
              h(NCheckbox, {
                checked,
                indeterminate,
                onUpdateChecked: (checked) => {
                  stations.value.forEach((station) => {
                    onUpdatePermissionChecked(checked, station.code, permissionType);
                  });
                },
              }),
              h('span', title),
            ],
          },
        );
      },
      key: permissionType,
      align: 'center',
      render: (rowData) => {
        const { code: stationCode } = rowData;
        return h(NCheckbox, {
          checked: currentList.value.some((permission) => permission.stationCode === stationCode && permission.type === permissionType),
          onUpdateChecked: (checked) => onUpdatePermissionChecked(checked, stationCode, permissionType),
        });
      },
    })),
  ];
});

const { mutate: savePermissions, isPending: permissionsSaving } = useMutation({
  mutationFn: async () => {
    if (!employeeId.value) throw new Error('员工ID不能为空');

    abortController.value.abort();
    abortController.value = new AbortController();

    const signal = abortController.value.signal;

    // 执行diff计算，生成需要保存的权限列表和需要删除的权限ID列表
    const saveList: NdmPermissionSaveVO[] = [];
    const removeList: string[] = [];
    // 遍历当前状态，如果权限不在原始权限列表中，说明是需要新增的权限
    currentList.value.forEach((permission) => {
      const { stationCode, type } = permission;
      if (!stationCode || !type) return;
      if (!originalList.value.some((permission) => permission.stationCode === stationCode && permission.type === type)) {
        saveList.push({
          employeeId: employeeId.value,
          stationCode,
          type,
        });
      }
    });
    // 遍历原始状态，如果权限不在当前状态中，说明是需要删除的权限
    originalList.value.forEach((permission) => {
      const { id, stationCode, type } = permission;
      if (!id) return;
      if (!currentList.value.some((permission) => permission.stationCode === stationCode && permission.type === type)) {
        removeList.push(id);
      }
    });

    await modifyPermissionApi(
      {
        employeeId: employeeId.value,
        saveList,
        removeList,
      },
      {
        signal,
      },
    );
  },
  onSuccess: () => {
    window.$message.success('权限配置保存成功');
    getPermissions();
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const onAfterEnter = () => {
  getEmployeeAsync().then(() => getPermissions());
};

const onAfterLeave = () => {
  employee.value = undefined;
  originalList.value = [];
  currentList.value = [];
};

const onClose = () => {
  abortController.value.abort();
  show.value = false;
};
</script>

<template>
  <NModal
    v-model:show="show"
    preset="card"
    style="width: 100vw; height: 100vh"
    :content-style="{ height: '100%', overflow: 'hidden' }"
    :close-on-esc="false"
    :mask-closable="false"
    :auto-focus="false"
    @after-enter="onAfterEnter"
    @after-leave="onAfterLeave"
    @close="onClose"
  >
    <template #header>
      <span>{{ `配置权限 - ${employee?.realName ?? ''}` }}</span>
    </template>
    <template #default>
      <NDataTable flex-height style="height: 100%" :columns="tableColumns" :data="stations" :loading="permissionsLoading" :single-line="false" />
    </template>
    <template #footer>
      <NText depth="3" style="font-size: smaller">*未勾选任何权限的用户将被认为拥有所有权限</NText>
    </template>
    <template #action>
      <NFlex justify="end">
        <NButton size="small" @click="onClose">取消</NButton>
        <NButton type="primary" size="small" :loading="permissionsSaving" @click="() => savePermissions()">保存</NButton>
      </NFlex>
    </template>
  </NModal>
</template>

<style scoped lang="scss"></style>
