import type {
  ComponentRecordType,
  GenerateMenuAndRoutesOptions,
} from '@vben/types';

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

import { getAllMenusApi } from '#/api/core/menu';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
import { useAppContextStore } from '#/store/app-context';

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

const lightMenuNames = new Set([
  'AIAgent',
  'AIKnowledgeDetail',
  'AIPlatform',
  'AIWorkflow',
  'AIWorkflowRuns',
  'AnnouncementList',
  'AnnouncementManage',
  'Codex',
  'ControlCenter',
  'KnowledgeBase',
  'Message',
  'MessageList',
  'SubAppAIAgentEditor',
  'SubAppAIKnowledgeDetail',
  'SubAppAIWorkflowEditor',
  'SubAppAIWorkflowRuns',
  'SystemConfigManager',
  'SystemManagement',
  'SystemMenu',
  'SystemPermission',
  'SystemRole',
  'UserManagement',
]);

function normalizeViewPath(path: string) {
  const normalizedPath = path.replace(/^(\.\/|\.\.\/)+/, '');
  const viewPath = normalizedPath.startsWith('/')
    ? normalizedPath
    : `/${normalizedPath}`;
  return viewPath.replace(/^\/views/, '');
}

function hasPageComponent(
  component: string | undefined,
  pageMap: ComponentRecordType,
  layoutMap: ComponentRecordType,
) {
  if (!component) return true;
  if (layoutMap[component]) return true;

  const normalizedPath = normalizeViewPath(component);
  const pageKey = normalizedPath.endsWith('.vue')
    ? normalizedPath
    : `${normalizedPath}.vue`;

  return Boolean(pageMap[pageKey]);
}

function normalizePageMap(pageMap: ComponentRecordType) {
  return Object.fromEntries(
    Object.entries(pageMap).map(([key, value]) => [
      normalizeViewPath(key),
      value,
    ]),
  ) as ComponentRecordType;
}

function normalizeBackendRoute<
  T extends {
    component?: string;
    name?: string;
    path?: string;
    query?: unknown;
  },
>(route: T) {
  if (route.name !== 'ControlCenter') return route;

  const normalized = { ...route };
  normalized.path = '/page-render/main_home';
  normalized.component = 'online-dev/page-render/index';
  normalized.query = undefined;
  return normalized;
}

function isLightMenuRoute(route: { name?: string }) {
  return !route.name || lightMenuNames.has(route.name);
}

function filterAvailableRoutes<
  T extends {
    children?: T[];
    component?: string;
    name?: string;
    path?: string;
    query?: unknown;
  },
>(
  routes: T[],
  pageMap: ComponentRecordType,
  layoutMap: ComponentRecordType,
): T[] {
  return routes
    .filter(isLightMenuRoute)
    .map((route) => {
      const normalizedRoute = normalizeBackendRoute(route);
      const children = normalizedRoute.children
        ? filterAvailableRoutes(normalizedRoute.children, pageMap, layoutMap)
        : undefined;

      if (
        !normalizedRoute.component &&
        normalizedRoute.children &&
        !children?.length
      ) {
        return undefined;
      }

      if (!hasPageComponent(normalizedRoute.component, pageMap, layoutMap)) {
        if (!children?.length) return undefined;

        const groupRoute = { ...normalizedRoute, children };
        delete groupRoute.component;
        return groupRoute;
      }

      return children ? { ...normalizedRoute, children } : normalizedRoute;
    })
    .filter(Boolean) as T[];
}

async function generateAccess(options: GenerateMenuAndRoutesOptions) {
  const pageMap: ComponentRecordType = import.meta.glob([
    '../views/_core/agent-chat/**/*.vue',
    '../views/_core/ai-confirmation-center/index.vue',
    '../views/_core/announcement/index.vue',
    '../views/_core/announcement/list.vue',
    '../views/_core/authentication/login.vue',
    '../views/_core/authentication/oauth-callback.vue',
    '../views/_core/fallback/**/*.vue',
    '../views/_core/file-preview/index.vue',
    '../views/_core/menu/index.vue',
    '../views/_core/message/index.vue',
    '../views/_core/permission/index.vue',
    '../views/_core/role/index.vue',
    '../views/_core/system-config/index.vue',
    '../views/_core/user/index.vue',
    '../views/ai-platform/agent/editor/index.vue',
    '../views/ai-platform/agent/index.vue',
    '../views/ai-platform/knowledge/detail/index.vue',
    '../views/ai-platform/knowledge/index.vue',
    '../views/ai-platform/model/index.vue',
    '../views/ai-platform/workflow/editor/index.vue',
    '../views/ai-platform/workflow/index.vue',
    '../views/ai-platform/workflow-runs/index.vue',
    '../views/online-dev/page-render/index.vue',
  ]);

  const layoutMap: ComponentRecordType = {
    BasicLayout,
    IFrameView,
    Layout: BasicLayout,
    'Layout.vue': BasicLayout,
    '/Layout.vue': BasicLayout,
  };
  const routePageMap = normalizePageMap(pageMap);

  return await generateAccessible(preferences.app.accessMode, {
    ...options,
    fetchMenuListAsync: async () => {
      const { ElMessage } =
        await import('element-plus/es/components/message/index');
      ElMessage({
        duration: 1500,
        message: `${$t('common.loadingMenu')}...`,
      });

      // 获取应用上下文
      const appContextStore = useAppContextStore();

      // 如果是子应用模式，传递 appCode 过滤应用专属菜单
      if (appContextStore.appCode) {
        const menus = await getAllMenusApi(appContextStore.appCode);
        return filterAvailableRoutes(menus, routePageMap, layoutMap);
      }

      // 主应用模式，不传参数
      const menus = await getAllMenusApi();
      return filterAvailableRoutes(menus, routePageMap, layoutMap);
    },
    // 可以指定没有权限跳转403页面
    forbiddenComponent,
    // 如果 route.meta.menuVisibleWithForbidden = true
    layoutMap,
    pageMap,
  });
}

export { generateAccess };
