/**
 * KRA - Async Router Utility Functions
 * Route generation from menu data for UMI
 */

export interface MenuItem {
  ID?: number;
  name: string;
  path: string;
  component?: string;
  redirect?: string;
  hidden?: boolean;
  meta?: {
    title?: string;
    icon?: string;
    keepAlive?: boolean;
    defaultMenu?: boolean;
    closeTab?: boolean;
    path?: string;
  };
  children?: MenuItem[];
  parameters?: Array<{ key: string; value: string }>;
}

export interface RouteConfig {
  path: string;
  name?: string;
  component?: string;
  redirect?: string;
  hideInMenu?: boolean;
  meta?: Record<string, any>;
  routes?: RouteConfig[];
}

/**
 * Convert menu item to UMI route config
 * @param menu - Menu item from backend
 * @returns UMI route config
 */
const menuToRoute = (menu: MenuItem): RouteConfig => {
  const route: RouteConfig = {
    path: menu.path,
    name: menu.name,
    hideInMenu: menu.hidden,
    meta: {
      title: menu.meta?.title || menu.name,
      icon: menu.meta?.icon,
      keepAlive: menu.meta?.keepAlive,
      defaultMenu: menu.meta?.defaultMenu,
      closeTab: menu.meta?.closeTab,
    },
  };

  if (menu.component) {
    route.component = menu.component;
    if (route.meta) {
      route.meta.componentPath = menu.component;
    }
  }

  if (menu.redirect) {
    route.redirect = menu.redirect;
  }

  // Handle route parameters
  if (menu.parameters && menu.parameters.length > 0) {
    const params: Record<string, string> = {};
    menu.parameters.forEach((param) => {
      params[param.key] = param.value;
    });
    if (route.meta) {
      route.meta.params = params;
    }
  }

  return route;
};

/**
 * Process async router data from backend
 * @param asyncRouter - Menu data from backend
 * @returns Processed route configs
 */
export const asyncRouterHandle = (asyncRouter: MenuItem[]): RouteConfig[] => {
  const routes: RouteConfig[] = [];

  asyncRouter.forEach((item) => {
    const route = menuToRoute(item);

    if (item.children && item.children.length > 0) {
      route.routes = asyncRouterHandle(item.children);
    }

    routes.push(route);
  });

  return routes;
};

/**
 * Flatten routes to single level array
 * @param routes - Nested route configs
 * @returns Flat route array
 */
export const flattenRoutes = (routes: RouteConfig[]): RouteConfig[] => {
  const result: RouteConfig[] = [];

  const traverse = (items: RouteConfig[], parentPath: string = '') => {
    items.forEach((route) => {
      const fullPath = route.path.startsWith('/')
        ? route.path
        : `${parentPath}/${route.path}`.replace(/\/+/g, '/');

      result.push({
        ...route,
        path: fullPath,
        routes: undefined,
      });

      if (route.routes && route.routes.length > 0) {
        traverse(route.routes, fullPath);
      }
    });
  };

  traverse(routes);
  return result;
};

/**
 * Build route map for quick lookup
 * @param routes - Route configs
 * @returns Map of path to route
 */
export const buildRouteMap = (routes: RouteConfig[]): Map<string, RouteConfig> => {
  const map = new Map<string, RouteConfig>();
  const flatRoutes = flattenRoutes(routes);

  flatRoutes.forEach((route) => {
    if (route.path) {
      map.set(route.path, route);
    }
    if (route.name) {
      map.set(route.name, route);
    }
  });

  return map;
};

/**
 * Find route by name
 * @param routes - Route configs
 * @param name - Route name
 * @returns Found route or undefined
 */
export const findRouteByName = (
  routes: RouteConfig[],
  name: string
): RouteConfig | undefined => {
  for (const route of routes) {
    if (route.name === name) {
      return route;
    }
    if (route.routes && route.routes.length > 0) {
      const found = findRouteByName(route.routes, name);
      if (found) return found;
    }
  }
  return undefined;
};

/**
 * Filter routes by access
 * @param routes - Route configs
 * @param accessiblePaths - Accessible path list
 * @returns Filtered routes
 */
export const filterRoutesByAccess = (
  routes: RouteConfig[],
  accessiblePaths: string[]
): RouteConfig[] => {
  return routes
    .filter((route) => {
      return accessiblePaths.includes(route.path) || route.routes?.length;
    })
    .map((route) => {
      if (route.routes && route.routes.length > 0) {
        return {
          ...route,
          routes: filterRoutesByAccess(route.routes, accessiblePaths),
        };
      }
      return route;
    })
    .filter((route) => {
      // Remove parent routes with no accessible children
      if (route.routes && route.routes.length === 0 && !route.component) {
        return false;
      }
      return true;
    });
};

export default {
  asyncRouterHandle,
  flattenRoutes,
  buildRouteMap,
  findRouteByName,
  filterRoutesByAccess,
};
