import type {
  ComponentRecordType,
  GenerateMenuAndRoutesOptions,
} from '@vben/types';
import type { RouteRecordRaw } from 'vue-router';

import { generateAccessible } from '@vben/access';
import { preferences } from '@vben/preferences';

import { message } from 'antdv-next';

import { getAllMenusApi, getLegacyMenusApi, type LegacyMenu } from '#/api';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';

const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');

const ROUTE_MENU_OVERRIDES: Record<
  string,
  {
    aliases?: string[];
    routers?: string[];
    titles?: string[];
  }
> = {
  BdLead: { aliases: ['BdLead'], routers: ['team/bd-lead'] },
  DynamicTagList: { aliases: ['DynamicTag'], routers: ['dynamic/tag'] },
  DynamicUserList: { aliases: ['UserDynamicList'], routers: ['user/dynamic/list'] },
  OperateBusinessDevelopment: {
    aliases: ['BusinessDevelopment'],
    routers: ['room/business-development'],
    titles: ['BD列表'],
  },
  PayCountry: {
    aliases: ['openPayCountry'],
    routers: ['open_pay/country'],
    titles: ['开通支付国家'],
  },
  PropsResourceConfig: { aliases: ['PropsConfig'], routers: ['props/config'] },
  PropsSourceGroup: {
    aliases: ['PropsActivityRewardCnf'],
    routers: ['props/props_source_group'],
  },
  SystemMenusManager: { aliases: ['MenusManager'], routers: ['menus'] },
  SystemResourceManager: { aliases: ['ResourceManager'], routers: ['resource'] },
  SystemRoleManager: { aliases: ['RolesManager'], routers: ['roles'] },
  SystemUserManager: { aliases: ['UserManager'], routers: ['user'] },
  TeamBillList: { aliases: ['TeamBill'], routers: ['team/bill'] },
  TeamMemberList: { aliases: ['TeamMember'], routers: ['team/member'] },
  UserDiamondBalance: {
    aliases: ['GameDoubleLayerFruit'],
    routers: ['/user/diamond-balance'],
  },
  UserDiamondRunWater: {
    aliases: ['GameDoubleLayerFruit'],
    routers: ['/user/diamond-run-water'],
  },
};

function normalizeRoutePath(path?: string | null) {
  return String(path || '')
    .trim()
    .replace(/^\/+/, '')
    .replace(/\/+$/, '');
}

function collectRouteAliases(route: RouteRecordRaw) {
  const values: string[] = [];
  if (route.name) {
    values.push(String(route.name));
  }
  const override = ROUTE_MENU_OVERRIDES[String(route.name || '')];
  if (override?.aliases) {
    values.push(...override.aliases);
  }
  return new Set(values.filter(Boolean));
}

function collectRoutePaths(route: RouteRecordRaw) {
  const values = [normalizeRoutePath(route.path)];
  const aliases = Array.isArray(route.alias)
    ? route.alias
    : route.alias
      ? [route.alias]
      : [];
  values.push(...aliases.map((item) => normalizeRoutePath(String(item))));
  const override = ROUTE_MENU_OVERRIDES[String(route.name || '')];
  if (override?.routers) {
    values.push(...override.routers.map((item) => normalizeRoutePath(item)));
  }
  return new Set(values.filter(Boolean));
}

function collectRouteTitles(route: RouteRecordRaw) {
  const values = [String(route.meta?.title || '').trim()];
  const override = ROUTE_MENU_OVERRIDES[String(route.name || '')];
  if (override?.titles) {
    values.push(...override.titles.map((item) => item.trim()));
  }
  return new Set(values.filter(Boolean));
}

function buildAuthorizedMenuMatcher(menus: LegacyMenu[]) {
  const aliasSet = new Set<string>();
  const routerSet = new Set<string>();
  const titleSet = new Set<string>();
  const queue = [...menus];

  while (queue.length > 0) {
    const item = queue.shift();
    if (!item) {
      continue;
    }
    if (item.alias) {
      aliasSet.add(String(item.alias));
    }
    if (item.router) {
      routerSet.add(normalizeRoutePath(item.router));
    }
    if (item.menuType === 2 && item.menuName) {
      titleSet.add(String(item.menuName).trim());
    }
    if (Array.isArray(item.childrens) && item.childrens.length > 0) {
      queue.push(...item.childrens);
    }
  }

  return (route: RouteRecordRaw) => {
    for (const alias of collectRouteAliases(route)) {
      if (aliasSet.has(alias)) {
        return true;
      }
    }
    for (const path of collectRoutePaths(route)) {
      if (routerSet.has(path)) {
        return true;
      }
    }
    for (const title of collectRouteTitles(route)) {
      if (titleSet.has(title)) {
        return true;
      }
    }
    return false;
  };
}

function filterRoutesByAuthorizedMenus(
  routes: RouteRecordRaw[],
  isAuthorized: (route: RouteRecordRaw) => boolean,
): RouteRecordRaw[] {
  return routes.flatMap((route) => {
    const nextRoute: RouteRecordRaw = { ...route };
    const children = route.children
      ? filterRoutesByAuthorizedMenus(route.children, isAuthorized)
      : [];

    if (route.meta?.ignoreAccess || route.meta?.hideInMenu) {
      nextRoute.children = children;
      return [nextRoute];
    }

    if (children.length > 0) {
      nextRoute.children = children;
      return [nextRoute];
    }

    delete nextRoute.children;
    return isAuthorized(route) ? [nextRoute] : [];
  });
}

async function generateAccess(options: GenerateMenuAndRoutesOptions) {
  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');

  const layoutMap: ComponentRecordType = {
    BasicLayout,
    IFrameView,
  };

  let routes = options.routes || [];

  if (preferences.app.accessMode === 'frontend') {
    message.loading({
      content: `${$t('common.loadingMenu')}...`,
      duration: 1.5,
    });
    const legacyMenus = await getLegacyMenusApi();
    const isAuthorized = buildAuthorizedMenuMatcher(legacyMenus);
    routes = filterRoutesByAuthorizedMenus(routes, isAuthorized);
  }

  return await generateAccessible(preferences.app.accessMode, {
    ...options,
    routes,
    fetchMenuListAsync: async () => {
      message.loading({
        content: `${$t('common.loadingMenu')}...`,
        duration: 1.5,
      });
      return await getAllMenusApi();
    },
    // 可以指定没有权限跳转403页面
    forbiddenComponent,
    // 如果 route.meta.menuVisibleWithForbidden = true
    layoutMap,
    pageMap,
  });
}

export { generateAccess };
