import type { MenuPermissionOption } from './data';

import type { useVbenVxeGrid } from '#/adapter/vxe-table';
import type { SysMenuApi } from '#/api/auth/menu';

import { eachTree, treeToList } from '@vben/utils';

import { notification } from 'ant-design-vue';
import { difference, isEmpty, isUndefined } from 'lodash-es';

type MenuOption = SysMenuApi.MenuOption;
/**
 * 权限列设置是否全选
 * @param record 行记录
 * @param checked 是否选中
 */
export function setPermissionsChecked(
  record: MenuPermissionOption,
  checked: boolean,
) {
  if (record?.permissions?.length > 0) {
    // 全部设置为选中
    record.permissions.forEach((permission) => {
      permission.checked = checked;
    });
  }
}

/**
 * 设置当前行 & 所有子节点选中状态
 * @param record 行
 * @param checked 是否选中
 */
export function rowAndChildrenChecked(
  record: MenuPermissionOption,
  checked: boolean,
) {
  // 当前行选中
  setPermissionsChecked(record, checked);
  // 所有子节点选中
  record?.children?.forEach?.((permission) => {
    rowAndChildrenChecked(permission as MenuPermissionOption, checked);
  });
}

/**
 * void方法 会直接修改原始数据
 * 将树结构转为 tree+permissions结构
 * @param menus 后台返回的menu
 */
export function menusWithPermissions(menus: MenuOption[]) {
  eachTree(menus, (item: MenuPermissionOption) => {
    validateMenuTree(item);
    if (item.children && item.children.length > 0) {
      /**
       * 所有为按钮的节点提取出来
       * 需要注意 这里需要过滤目录下直接是按钮的情况item.menuType !== 0
       * 将按钮往children添加而非加到permissions
       */
      const permissions = item.children.filter(
        (child: MenuOption) => child.type === 2 && item.type !== 0,
      );
      // 取差集
      const diffCollection = difference(item.children, permissions);
      // 更新后的children  即去除按钮
      item.children = diffCollection;

      // permissions作为字段添加到item
      const permissionsArr = permissions.map((permission) => {
        return {
          id: permission.id,
          label: permission.name,
          checked: false,
        };
      });
      item.permissions = permissionsArr;
    }
  });
}

/**
 * 设置表格选中
 * @param checkedKeys 选中的keys
 * @param menus 菜单 转换后的菜单
 * @param tableApi api
 * @param association 是否节点关联
 */
export function setTableChecked(
  checkedKeys: (number | string)[],
  menus: MenuPermissionOption[],
  tableApi: ReturnType<typeof useVbenVxeGrid>['1'],
  association: boolean,
) {
  // tree转list
  const menuList: MenuPermissionOption[] = treeToList(menus);
  // 拿到勾选的行数据
  let checkedRows = menuList.filter((item) => checkedKeys.includes(item.id));

  /**
   * 节点独立切换到节点关联 只需要最末尾的数据 即children为空
   */
  if (!association) {
    checkedRows = checkedRows.filter(
      (item) => isUndefined(item.children) || isEmpty(item.children),
    );
  }

  // 设置行选中 & permissions选中
  checkedRows.forEach((item) => {
    tableApi.grid.setCheckboxRow(item, true);
    if (item?.permissions?.length > 0) {
      item.permissions.forEach((permission) => {
        if (checkedKeys.includes(permission.id)) {
          permission.checked = true;
        }
      });
    }
  });

  /**
   * 节点独立切换到节点关联
   * 勾选后还需要过滤权限没有任何勾选的情况 这时候取消行的勾选
   */
  if (!association) {
    const emptyRows = checkedRows.filter((item) => {
      if (isUndefined(item.permissions) || isEmpty(item.permissions)) {
        return false;
      }
      return item.permissions.every(
        (permission) => permission.checked === false,
      );
    });
    // 设置为不选中
    tableApi.grid.setCheckboxRow(emptyRows, false);
  }
}

/**
 * 校验是否符合规范 给出warning提示
 *
 * 不符合规范
 * 比如: 菜单下放目录 菜单下放菜单
 * 比如: 按钮下放目录 按钮下放菜单 按钮下放按钮
 * @param menu menu
 */
function validateMenuTree(menu: MenuOption) {
  /**
   * C: { icon: markRaw(MenuIcon), value: '菜单' },
      F: { icon: markRaw(OkButtonIcon), value: '按钮' },
      M: { icon: markRaw(FolderIcon), value: '目录' },
   */
  // 菜单下不能放目录/菜单
  if (menu.type === 1) {
    menu.children?.forEach?.((item) => {
      if ([0, 1].includes(item.type)) {
        const description = `错误用法: [${menu.name} - 菜单]下不能放 目录/菜单 -> [${item.name}]`;
        console.warn(description);
        notification.warning({
          message: '提示',
          description,
          duration: 0,
        });
      }
    });
  }
  // 按钮为最末级 不能再放置
  if (menu.type === 2) {
    /**
     * 其实可以直接判断length 这里为了更准确知道label 采用遍历的形式
     */
    menu.children?.forEach?.((item) => {
      if ([0, 1, 2].includes(item.type)) {
        const description = `错误用法: [${menu.name} - 按钮]下不能放置'目录/菜单/按钮' -> [${item.name}]`;
        console.warn(description);
        notification.warning({
          message: '提示',
          description,
          duration: 0,
        });
      }
    });
  }
}
