import { useMemo, useRef } from 'react';
import type { IResourceItem, ResourceProps } from '@refinedev/core';
import { DashboardOutlined, SettingOutlined } from '@ant-design/icons';
import { getRoutePath } from 'config/routeRegistry';
import { useUserPageAccess } from './useUserPageAccess';
import generatedResources from 'generated/resources';

/**
 * Dynamic Resources Hook for erp-backend/web
 *
 * Features:
 * 1. Get user accessible page resources from backend (via useUserPageAccess)
 * 2. Convert backend data to Refine's IResourceItem[] format
 * 3. Auto-generate show/edit/create paths for all pages
 *
 * Data Flow:
 * useUserPageAccess → Accessible Pages → Resources → Sider Menu
 *
 * Performance:
 * - Uses module-level cache - computed ONCE per page load
 * - Returns same reference on every call after initial computation
 * - Does NOT rebuild on route navigation or component re-renders
 * - Permission changes require page refresh (handled by user)
 */

// Module-level cache - computed once per page load
let cachedResources: IResourceItem[] | null = null;
let isComputing = false;

// 将 snake_case 转换为 camelCase
function snakeToCamel(str: string): string {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}

// Icon 映射：page.code 到 React Icon 组件
export const iconMapping: Record<string, React.ReactNode> = {
  dashboard: <DashboardOutlined />,
  administration: <SettingOutlined />,
};

// Pages whose children are tabs (not separate menu items)
const PAGES_WITH_TABS: string[] = [];

export const useDynamicResources = (): IResourceItem[] => {
  // Use shared page access data (single call, reused below)
  const { accessiblePageIds, pagesData, pageMap, isLoading, roleNames } =
    useUserPageAccess();

  // If we already have cached resources, return immediately
  if (cachedResources !== null) {
    return cachedResources;
  }

  // Return empty array while loading (will retry on next render)
  if (isLoading || !pagesData || isComputing) {
    return [];
  }

  // Mark as computing to prevent concurrent computation
  isComputing = true;

  if (import.meta.env.DEV) {
    console.log('[useDynamicResources] 🔨 Computing resources (first time)');
  }

  // Filter accessible pages and build hierarchical sorted list
  const accessiblePages = pagesData.filter((page) =>
    accessiblePageIds.has(page.id),
  );

  // Group pages by parentId
  const pagesByParent = new Map<number | null, typeof accessiblePages>();
  accessiblePages.forEach((page) => {
    const parentId = page.parentId ?? null;
    if (!pagesByParent.has(parentId)) {
      pagesByParent.set(parentId, []);
    }
    pagesByParent.get(parentId)!.push(page);
  });

  // Sort each group by sortOrder
  pagesByParent.forEach((pages) => {
    pages.sort((a, b) => (a.sortOrder ?? Infinity) - (b.sortOrder ?? Infinity));
  });

  // Build sorted list using depth-first traversal
  const sortedAccessiblePages: typeof accessiblePages = [];
  const visited = new Set<number>();

  const addPageWithChildren = (parentId: number | null) => {
    const children = pagesByParent.get(parentId) || [];
    children.forEach((page) => {
      if (visited.has(page.id)) return;
      visited.add(page.id);
      sortedAccessiblePages.push(page);
      addPageWithChildren(page.id);
    });
  };

  // Start from root level (parentId = null)
  addPageWithChildren(null);

  // Add any orphaned pages
  accessiblePages.forEach((page) => {
    if (!visited.has(page.id)) {
      sortedAccessiblePages.push(page);
    }
  });

  // 检测哪些父页面有"index 子页面"（子页面路径与父页面相同，即 path: "" 的 index 路由）
  // 这类父页面应作为纯分组节点（不注册 list 路径），否则 Refine 会优先选中父节点
  // 导致 "全部" 等 index 子菜单项无法高亮
  const parentIdsWithIndexChild = new Set<number>();
  accessiblePages.forEach((childPage) => {
    if (!childPage.parentId) return;
    const childPath = getRoutePath(childPage.code);
    if (!childPath) return;
    const parentPage = pageMap.get(childPage.parentId);
    if (!parentPage) return;
    const parentPath = getRoutePath(parentPage.code);
    if (childPath === parentPath) {
      parentIdsWithIndexChild.add(childPage.parentId);
    }
  });

  // Build resources
  const resultResources: IResourceItem[] = [];
  const addedResourceNames = new Set<string>();

  sortedAccessiblePages.forEach((page) => {
    if (!page) return;

    // NOTE: isVirtual pages are NOT skipped here — keeping them in the
    // resources array lets Refine hooks (useResource, useNavigation, etc.)
    // resolve the page's metadata, and React Router routes for these
    // pages are registered independently via routeRegistry. The menu
    // entry is hidden below by setting `meta.hide = true`, which
    // Refine's useMenu honours.

    // Skip children of pages that use tabs
    if (page.parentId) {
      const parentPage = pageMap.get(page.parentId);
      if (parentPage && PAGES_WITH_TABS.includes(parentPage.code)) {
        return;
      }
    }

    const permissionRes = snakeToCamel(page.code);

    // Avoid duplicates
    if (addedResourceNames.has(permissionRes)) return;

    let parentPermissionRes: string | undefined;
    if (page.parentId) {
      const parentPage = pageMap.get(page.parentId);
      if (parentPage) {
        parentPermissionRes = snakeToCamel(parentPage.code);
      }
    }

    // 优先从 routeRegistry 获取路径
    // fallback 到 page.path（用于 gadmin2 页面）
    const registryPath = getRoutePath(page.code);
    const dbPath = page.path
      ? page.path.startsWith('/')
        ? page.path
        : `/${page.path}`
      : undefined;
    const normalizedPath = registryPath ?? dbPath;

    // 如果该页面是"有 index 子页面的父节点"，则不注册 list/show/edit/create
    // 使其成为纯分组节点（SubMenu），子页面（如"全部"）的路径才负责 URL 匹配与菜单高亮
    const isGroupParent = parentIdsWithIndexChild.has(page.id);

    // Build resource item with auto-generated CRUD paths
    // Store both zhLabel/enLabel in meta; Sider resolves at render time
    const resource: IResourceItem = {
      name: permissionRes,
      ...(!isGroupParent &&
        normalizedPath && {
          list: normalizedPath,
          show: `${normalizedPath}/show/:id`,
          edit: `${normalizedPath}/edit/:id`,
          create: `${normalizedPath}/create`,
          clone: `${normalizedPath}/clone/:id`,
        }),
      meta: {
        label: page.enName || page.code,
        zhLabel: page.zhName || page.code,
        enLabel: page.enName || page.code,
        icon: iconMapping[page.code] || '',
        parent: parentPermissionRes,
        route: normalizedPath,
        pageCode: page.code,
        parentPageCode: page.parentId
          ? pageMap.get(page.parentId)?.code
          : undefined,
        // Refine's useMenu skips items whose meta.hide === true.
        // This lets us hide a CRUD page from the auto-generated
        // 「数据管理」menu (e.g. AgendaJob is surfaced from the Cron
        // Jobs custom page instead) while keeping the route reachable.
        ...(page.isVirtual && { hide: true }),
      },
    };

    resultResources.push(resource);
    addedResourceNames.add(permissionRes);
  });

  // Build final resources array with auto-crud if needed
  const dynamicResources = resultResources;
  const allResources = dynamicResources;

  // 防御性保护：用户已有角色但算出来 0 个资源，说明 rolePagesData
  // 还没到位（isLoading 误报为 false 时进了这条分支），不要把空结果
  // 永久写入 cachedResources，否则后续真正加载完成后无法重算
  if (allResources.length === 0 && roleNames.length > 0) {
    isComputing = false;
    if (import.meta.env.DEV) {
      console.warn(
        '[useDynamicResources] ⚠️ Skip caching: 0 resources but roles present',
        { roleNames },
      );
    }
    return [];
  }

  // Cache the result - will be used for all subsequent calls
  cachedResources = allResources;
  isComputing = false;

  if (import.meta.env.DEV) {
    console.log(
      '[useDynamicResources] ✅ Resources cached. Count:',
      cachedResources.length,
    );
    console.log(
      '[useDynamicResources] 📌 This reference will be reused for all future calls',
    );
  }

  return cachedResources;
};
