import { RouteRecordRaw } from 'vue-router';

import { useAppStore } from '/@/store/modules/app';
import { usePermissionStore } from '/@/store/modules/permission';
import { useUserStore } from '/@/store/modules/user';

import { useTabs } from './useTabs';

import { router, resetRouter } from '/@/router';
// import { RootRoute } from '/@/router/routes';

import projectSetting from '/@/settings/projectSetting';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { RoleEnum } from '/@/enums/roleEnum';

import { cloneDeep, intersection } from 'lodash-es';
import { isArray } from '/@/utils/is';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { MenuAuthModel } from '/@/api/system/login/model';
import { BasicColumn, FormSchema } from '/@/components/Table';
import { toRaw } from 'vue';
import { camelCaseString } from '/@/utils/event/design';
import { ButtonConfig } from '/@/model/generator/listConfig';

// User permissions related operations
export function usePermission() {
  const userStore = useUserStore();
  const appStore = useAppStore();
  //获取到当前路由
  const currentRoute = router.currentRoute;
  const permissionStore = usePermissionStore();
  const { closeAll } = useTabs(router);

  /**
   * Change permission mode
   */
  async function togglePermissionMode() {
    appStore.setProjectConfig({
      permissionMode:
        projectSetting.permissionMode === PermissionModeEnum.BACK
          ? PermissionModeEnum.ROUTE_MAPPING
          : PermissionModeEnum.BACK,
    });
    location.reload();
  }

  /**
   * Reset and regain authority resource information
   * @param id
   */
  async function resume() {
    const tabStore = useMultipleTabStore();
    tabStore.clearCacheTabs();
    resetRouter();
    const routes = await permissionStore.buildRoutesAction(true);
    routes.forEach((route) => {
      router.addRoute(route as unknown as RouteRecordRaw);
    });
    permissionStore.setLastBuildMenuTime();
    closeAll();
  }

  /**
   * Determine whether there is permission
   */
  function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
    // Visible by default
    if (!value) {
      return def;
    }

    const permMode = projectSetting.permissionMode;

    if ([PermissionModeEnum.ROUTE_MAPPING, PermissionModeEnum.ROLE].includes(permMode)) {
      if (!isArray(value)) {
        return userStore.getRoleList?.includes(value as RoleEnum);
      }
      return (intersection(value, userStore.getRoleList) as RoleEnum[]).length > 0;
    }

    if (PermissionModeEnum.BACK === permMode) {
      const allPerm = permissionStore.getPermCodeList as MenuAuthModel[];
      const { menuId } = currentRoute.value.meta;
      const thisMenuAuth = allPerm.find((p) => p.menuId === menuId);
      return thisMenuAuth?.buttonAuthCode?.includes(value as string) || false;
      // if (!isArray(allPerm)) {
      //   const { menuId } = currentRoute.value.meta;

      //   const auth = allPerm.find((p) => p.menuId === menuId);
      //   return allCodeList.includes(value);
      // }
      // return (intersection(value, allCodeList) as string[]).length > 0;
    }
    return true;
  }

  /**
   * Change roles
   * @param roles
   */
  async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {
    if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) {
      throw new Error(
        'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!',
      );
    }

    if (!isArray(roles)) {
      roles = [roles];
    }
    userStore.setRoleList(roles);
    await resume();
  }

  /**
   * refresh menu data
   */
  async function refreshMenu() {
    resume();
  }

  /**
   * refresh menu data
   */
  async function changeMenu() {}

  /**
   * button
   * @param buttonList 未过滤的
   * @returns 过滤后的
   */
  function filterButtonAuth(buttonList: ButtonConfig[]) {
    //获取到当前菜单id
    const menuId = currentRoute.value.meta.menuId;
    const perm = permissionStore.getPermCodeList.find((x) => x.menuId === menuId);
    if (!perm) return buttonList;
    let buttonAuth = perm?.buttonAuthCode || [];
    if (!buttonAuth || buttonAuth?.length === 0) {
      return [];
    }
    buttonAuth = buttonAuth.map((x) => {
      const btnList = x.split(':');
      btnList.shift();
      return btnList.join('');
    });
    const result = buttonList.filter((btn) => buttonAuth.includes(btn.code));
    return result;
  }

  /**
   * BasicColumn
   * @param columns 未过滤的
   * @param convertCamel  是否需要转驼峰
   * @returns 过滤后的
   */
  function filterColumnAuth(columns: BasicColumn[], convertCamel = false): BasicColumn[] {
    //获取到当前菜单id
    const menuId = currentRoute.value.meta.menuId;
    const perm = permissionStore.getPermCodeList.find((x) => x.menuId === menuId);

    if (!perm) return columns;

    let columnAuth = perm?.columnAuthCode || [];
    if (!columnAuth || columnAuth?.length === 0) {
      return [];
    }
    if (convertCamel) {
      columnAuth = columnAuth.map((x) => camelCaseString(x)!);
    }
    const result = columns.filter(
      (col) => col.dataIndex && toRaw(columnAuth).includes(col.dataIndex as string),
    );

    return result;
  }
  /**
   * 表头合并
   * @param columns 未过滤的
   * @param convertCamel  是否需要转驼峰
   * @returns 过滤后的
   */
  function filterHeaderColumnAuth(columns: BasicColumn[], convertCamel = false): BasicColumn[] {
    //获取到当前菜单id
    const menuId = currentRoute.value.meta.menuId;
    const perm = permissionStore.getPermCodeList.find((x) => x.menuId === menuId);

    if (!perm) return columns;

    let columnAuth = perm?.columnAuthCode || [];
    if (!columnAuth || columnAuth?.length === 0) {
      return [];
    }
    if (convertCamel) {
      columnAuth = columnAuth.map((x) => camelCaseString(x)!);
    }
    const result: BasicColumn[] = getChildAuth(cloneDeep(columns), columnAuth);
    return result;
  }
  function getChildAuth(arr, columnAuth) {
    const result: BasicColumn[] = [];
    arr.forEach((element) => {
      if (element.children && Array.isArray(element.children) && element.children.length > 0) {
        element.children = getChildAuth(cloneDeep(element.children), columnAuth);
        result.push(element);
      } else {
        if (element.dataIndex && toRaw(columnAuth).includes(element.dataIndex as string)) {
          result.push(element);
        }
      }
    });
    return result;
  }
  /**
   *  FormSchema权限过滤
   * @param formSchema 未过滤的FormSchema
   * @param convertCamel 是否需要转换驼峰
   * @returns 返回过滤过的FormSchema
   */
  function filterFormSchemaAuth(formSchema: FormSchema[], convertCamel = false): FormSchema[] {
    const menuId = currentRoute.value.meta.menuId;
    const perm = permissionStore.getPermCodeList.find((x) => x.menuId === menuId);
    if (!perm) return formSchema;
    let formAuth: any[] = perm?.formAuthCode || [];
    if (!formAuth || formAuth?.length === 0) {
      return [];
    }
    if (convertCamel) {
      formAuth = formAuth.map((x) => {
        if (typeof x === 'object' && !!Object.keys(x)[0]) {
          const subformField = camelCaseString(Object.keys(x)[0])!;
          x[subformField!] = x[subformField!]?.map((field) => camelCaseString(field));
          return {
            [subformField]: x[subformField!],
          };
        } else {
          return camelCaseString(x)!;
        }
      });
    }

    const result = formSchema.filter((schema) => {
      return findLayoutComponent(schema, formAuth);
    });
    return result;
  }

  function findLayoutComponent(schema, formAuth) {
    if (['card', 'tab', 'grid'].includes(schema.type)) {
      if (schema.children && schema.children.length > 0) {
        return schema.children.filter((children) => {
          children.list = children.list.filter((x) => findLayoutComponent(x, formAuth));
          return children.list;
        });
      }
    } else if (schema.type === 'table-layout') {
      if (schema.children && schema.children.length > 0) {
        return schema.children.filter((children) => {
          children.list = children.list.filter((chil) => {
            chil.children = chil.children.filter((x) => findLayoutComponent(x, formAuth));
            return chil.children;
          });
          return children.list;
        });
      }
    } else if (schema.type === 'form') {
      if (schema.componentProps.columns && schema.componentProps.columns.length) {
        const subformField = schema.field.substring(0, schema.field.length - 4);
        const currentSubFormAuth = formAuth.find((x) => {
          return typeof x === 'object' && Object.keys(x)[0] === subformField;
        });
        if (!currentSubFormAuth) {
          return false;
        } else {
          schema.componentProps.columns = schema.componentProps.columns.filter((x) => {
            return x.componentType
              ? findLayoutComponent(x, Object.values(currentSubFormAuth)[0])
              : true;
          });
          return true;
        }
      }
    } else if (schema.componentType == 'SunForm') {
      if (schema.componentProps.columns && schema.componentProps.columns.length) {
        const subformField = schema.mainKey.substring(0, schema.mainKey.length - 4);
        const currentSubFormAuth = formAuth.find((x) => {
          return typeof x === 'object' && Object.keys(x)[0] === subformField;
        });
        if (!currentSubFormAuth) {
          return false;
        } else {
          schema.componentProps.columns = schema.componentProps.columns.filter((x) => {
            return x.componentType
              ? findLayoutComponent(x, Object.values(currentSubFormAuth)[0])
              : true;
          });
          return true;
        }
      }
    } else if (schema.type === 'one-for-one') {
      if (schema.componentProps.childSchemas && schema.componentProps.childSchemas.length) {
        const subformField = schema.field.substring(0, schema.field.length - 4);
        const currentSubFormAuth = formAuth.find((x) => {
          return typeof x === 'object' && Object.keys(x)[0] === subformField;
        });
        if (!currentSubFormAuth) {
          return false;
        } else {
          schema.componentProps.childSchemas = schema.componentProps.childSchemas.filter((x) => {
            return x.component
              ? findLayoutComponent(x, Object.values(currentSubFormAuth)[0])
              : true;
          });
          return true;
        }
      }
    } else {
      const field = schema.field || schema.dataIndex || schema.key;
      return formAuth?.includes(field);
    }
  }

  return {
    changeRole,
    hasPermission,
    togglePermissionMode,
    refreshMenu,
    changeMenu,
    filterButtonAuth,
    filterColumnAuth,
    filterHeaderColumnAuth,
    getChildAuth,
    filterFormSchemaAuth,
  };
}
