import { routeCacheAtom, setRouteCache } from '@/atoms/route-cache';
import { userAtom } from '@/atoms/user';
import DarkMask from '@/components/dark-mask';
import '@/components/iconfont/iconfont.js';
import PluginExtraFields from '@/components/plugin-extra-fields';
import routeCachekey from '@/config/route-cachekey';
import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings';
import { COLOR_PRIMARY } from '@/config/theme';
import useCurrentUser from '@/hooks/use-current-user';
import useTableFetch from '@/hooks/use-table-fetch';
import useUserSettings from '@/hooks/use-user-settings';
import useUserSettingsStorage from '@/hooks/use-user-settings-storage';
import useAddResource from '@/pages/dashboard/hooks/use-add-resource';
import { logout } from '@/pages/login/apis';
import {
  readColumnSettings,
  readState,
  writeColumnSettings,
  writeState
} from '@/utils/localstore';
import { useAccessMarkedRoutes } from '@@/plugin-access';
import { useModel } from '@@/plugin-model';
import { ProLayout } from '@ant-design/pro-components';
import { CoreUIProvider, IconFont } from '@gpustack/core-ui';
import {
  Access,
  Outlet,
  dropByCacheKey,
  getAllLocales,
  history,
  matchRoutes,
  request,
  setLocale,
  useAccess,
  useAppData,
  useIntl,
  useLocation,
  useNavigate,
  type IRoute
} from '@umijs/max';
import { Button, ConfigProvider, Modal, theme } from 'antd';
import { useAtom } from 'jotai';
import 'overlayscrollbars/overlayscrollbars.css';
import { useMemo, useRef } from 'react';
import { PageContainerInner } from '../pages/_components/page-box';
import Exception from './Exception';
import './Layout.css';
import { LogoIcon, SLogoIcon } from './Logo';
import ErrorBoundary from './error-boundary';
import { ExtraContent } from './extraRender';
import { patchRoutes } from './runtime';
import SiderMenu from './sider-menu';

// Pages that use the page container in the page
const NO_CONTAINER_PAGES = [
  'chat',
  'rerank',
  'embedding',
  'speech',
  'image',
  'text2images',
  'clusterDetail',
  'clusterCreate',
  'benchmarkDetail',
  'deployment',
  'video'
];

const CHECK_RESOURCE_PATH = [
  '/resources/workers',
  '/resources/clusters/list',
  '/resources/credentials',
  '/resources/clusters/create'
];

type NewRoute = IRoute & {
  children?: IRoute[];
  routes?: IRoute[];
};

const loginPath = DEFAULT_ENTER_PAGE.login;

// Filter out the routes that need to be displayed, where filterFn indicates the levels that should not be shown
const filterRoutes = (
  routes: IRoute[],
  filterFn: (route: IRoute) => boolean
): any[] => {
  if (routes.length === 0) {
    return [];
  }

  const newRoutes: NewRoute[] = [];
  for (const route of routes) {
    const newRoute = { ...route };
    if (filterFn(route)) {
      if (Array.isArray(newRoute.routes)) {
        newRoutes.push(...filterRoutes(newRoute.routes, filterFn));
      }
    } else {
      if (Array.isArray(newRoute.children)) {
        newRoute.children = filterRoutes(newRoute.children, filterFn);
        newRoute.routes = newRoute.children;
      }
      newRoutes.push(newRoute);
    }
  }

  return newRoutes;
};

const mapRoutes = (routes: IRoute[], role: string) => {
  if (routes.length === 0) {
    return [];
  }
  return routes.map((route) => {
    const newRoute: NewRoute = { ...route, role };
    if (route.originPath) {
      newRoute.path = route.originPath;
    }

    if (Array.isArray(route.routes)) {
      newRoute.routes = mapRoutes(route.routes, role);
    }

    if (Array.isArray(route.children)) {
      newRoute.children = mapRoutes(route.children, role);
    }

    return newRoute;
  });
};

export default (props: any) => {
  const [, contextHolder] = Modal.useModal();
  const { themeData, setUserSettings, userSettings } = useUserSettings();
  const [userInfo] = useAtom(userAtom);
  const [routeCache] = useAtom(routeCacheAtom);
  const location = useLocation();
  const navigate = useNavigate();
  const intl = useIntl();
  const { clientRoutes } = useAppData();
  const requestResourceRef = useRef<boolean>(false);

  const { fetchResourceData, NoResourceModal } = useAddResource({
    onCreated() {
      requestResourceRef.current = false;
    }
  });

  const initialInfo = (useModel && useModel('@@initialState')) || {
    initialState: undefined,
    loading: false,
    setInitialState: null
  };

  const { initialState, loading, setInitialState } = initialInfo;
  const access = useAccess();

  const userConfig = {
    title: '',
    locale: true
  };

  const formatMessage = (args: { id: string }) => {
    return intl.formatMessage({ id: args.id });
  };

  const initRouteCacheValue = (pathname: string) => {
    if (routeCache.get(pathname) === undefined && routeCachekey[pathname]) {
      setRouteCache(pathname, false);
    }
  };

  const dropRouteCache = (pathname: string) => {
    for (const key of routeCache.keys()) {
      if (key !== pathname && !routeCache.get(key) && routeCachekey[key]) {
        dropByCacheKey(key);
        routeCache.delete(key);
      }
    }
  };

  const runtimeConfig = {
    ...initialInfo,
    logout: async () => {
      await logout();
      navigate(loginPath);
    },
    showVersion: () => {},
    showShortcuts: () => {},
    notFound: <span>404 not found</span>
  };

  const coreUISlots = useMemo(() => ({ ExtraContent }), []);

  const handleToggleCollapse = (e: any) => {
    e.stopPropagation();
    setUserSettings({
      ...userSettings,
      collapsed: !userSettings.collapsed
    });
  };
  const newRoutes = filterRoutes(
    // @ts-ignore
    clientRoutes.filter((route) => route.id === 'max-tabs'),
    (route) => {
      return (
        (!!route.isLayout && route.id !== '@@/global-layout') ||
        !!route.isWrapper
      );
    }
  );

  const role = initialState?.currentUser?.is_admin ? 'admin' : 'user';
  const [route] = useAccessMarkedRoutes(mapRoutes(newRoutes, role));
  console.log('route++++++++', route, clientRoutes);
  patchRoutes({
    routes: route.children,
    initialState: initialInfo.initialState
  });

  const matchedRoute = useMemo(
    () => matchRoutes(route?.children || [], location.pathname)?.pop?.()?.route,
    [location.pathname]
  );

  const isNoContainerPage = useMemo(() => {
    // @ts-ignore
    return NO_CONTAINER_PAGES.includes(matchedRoute?.name as string);
  }, [matchedRoute]);

  const collapsed = useMemo(() => {
    return userSettings.collapsed || false;
  }, [userSettings.collapsed]);

  const renderMenuHeader = (logo: React.ReactNode, title: React.ReactNode) => {
    return (
      <>
        {logo}
        <div className="collapse-wrap" onClick={handleToggleCollapse}>
          <Button
            style={{
              marginRight: collapsed ? 0 : -6,
              border: 'none',
              cursor: 'w-resize'
            }}
            size="small"
            type={collapsed ? 'default' : 'text'}
          >
            <IconFont
              type={collapsed ? 'icon-expand-left' : 'icon-expand-right'}
              className="font-size-18 text-secondary"
              style={{
                display: 'block'
              }}
            />
          </Button>
        </div>
      </>
    );
  };

  const menuContentRender = (menuProps: any, defaultDom: React.ReactNode) => {
    return <SiderMenu {...menuProps}></SiderMenu>;
  };

  const onPageChange = async (route: any) => {
    const { location } = history;
    const { pathname } = location;

    if (
      !CHECK_RESOURCE_PATH.includes(pathname) &&
      initialState?.currentUser?.is_admin &&
      !requestResourceRef.current &&
      !userSettings.hideAddResourceModal
    ) {
      requestResourceRef.current = true;
      await fetchResourceData();
    }

    initRouteCacheValue(pathname);
    dropRouteCache(pathname);

    // if user is not change password, redirect to change password page
    if (location.pathname !== loginPath && userInfo?.require_password_change) {
      history.push(loginPath);
      return;
    }

    // if user is not logged in, redirect to login page
    if (!initialState?.currentUser && location.pathname !== loginPath) {
      history.push(loginPath);
    } else if (location.pathname === '/') {
      // Pick a landing route the caller can actually see. Access
      // extensions can narrow ``canSeeAdmin`` to ``false`` even when
      // ``currentUser.is_admin`` is ``true``; pushing an admin to
      // ``/dashboard`` (gated by ``canSeeAdmin``) in that case
      // dead-ends in ``Exception`` 403 → redirect-to-``/`` →
      // re-push, looping into a blank screen. Honoring the resolved
      // predicate keeps the user on a route they can render.
      const pathname = access?.canSeeAdmin
        ? DEFAULT_ENTER_PAGE.adminForNormal
        : DEFAULT_ENTER_PAGE.user;
      history.push(pathname);
    }
  };

  const onMenuHeaderClick = (e: React.MouseEvent) => {
    e.stopPropagation();
    e.preventDefault();
    const pagepath = access?.canSeeAdmin
      ? DEFAULT_ENTER_PAGE.adminForNormal
      : DEFAULT_ENTER_PAGE.user;

    navigate(pagepath);
  };

  const onCollapse = (value: boolean) => {
    // only trigger by window resize
    if (!value) {
      return;
    }
    setUserSettings({
      ...userSettings,
      collapsed: value
    });
  };

  return (
    <ConfigProvider
      componentSize="large"
      theme={{
        algorithm: userSettings.isDarkTheme
          ? theme.darkAlgorithm
          : theme.defaultAlgorithm,
        ...themeData
      }}
      modal={{
        mask: {
          blur: false
        }
      }}
      drawer={{
        mask: {
          blur: false
        }
      }}
    >
      <CoreUIProvider
        config={{
          apiBaseUrl: GPUSTACK_API_BASE_URL,
          theme: userSettings.theme,
          iconUrl: '//at.alicdn.com/t/c/font_4613488_yo03vxgh67k.js',
          isDarkTheme: userSettings.isDarkTheme,
          defaultColorPrimary: COLOR_PRIMARY
        }}
        hooks={{
          useUserSettings,
          useUserSettingsStorage,
          useIntl,
          useCurrentUser,
          useTableFetch
        }}
        i18n={intl}
        locale={{
          getAllLocales: getAllLocales,
          setLocale: setLocale
        }}
        services={{
          request: request,
          router: {
            push: (path: string) => navigate(path),
            replace: (path: string) => navigate(path, { replace: true }),
            goBack: () => navigate(-1)
          }
        }}
        localStore={{
          readColumnSettings,
          writeColumnSettings,
          readState,
          writeState
        }}
        slots={coreUISlots}
        access={{ Access, useAccess }}
      >
        <DarkMask></DarkMask>
        <ProLayout
          fixSiderbar
          fixedHeader={false}
          headerRender={false}
          breadcrumbRender={false}
          route={route}
          location={location}
          title={userConfig.title}
          navTheme={userSettings.theme}
          layout="side"
          contentStyle={{
            paddingBlock: 0,
            paddingInline: 0
          }}
          openKeys={false}
          disableMobile={true}
          siderWidth={220}
          onCollapse={onCollapse}
          onMenuHeaderClick={onMenuHeaderClick}
          menuHeaderRender={renderMenuHeader}
          collapsed={userSettings.collapsed}
          onPageChange={onPageChange}
          formatMessage={formatMessage}
          menu={{
            locale: true,
            type: 'group'
          }}
          splitMenus={true}
          logo={userSettings.collapsed ? <SLogoIcon /> : <LogoIcon />}
          menuContentRender={menuContentRender}
          {...runtimeConfig}
          ErrorBoundary={ErrorBoundary}
        >
          <div
            style={{
              display: 'flex',
              flexDirection: 'column',
              height: '100vh',
              overflow: 'hidden'
            }}
          >
            <PluginExtraFields name="GlobalLicenseBanner" />
            <Exception
              route={matchedRoute}
              notFound={runtimeConfig?.notFound}
              noFound={runtimeConfig?.noFound}
              unAccessible={runtimeConfig?.unAccessible}
              noAccessible={runtimeConfig?.noAccessible}
            >
              {isNoContainerPage ? (
                <Outlet />
              ) : (
                <PageContainerInner>
                  <div>
                    <Outlet />
                  </div>
                </PageContainerInner>
              )}
            </Exception>
          </div>
          {NoResourceModal}
          {contextHolder}
        </ProLayout>
      </CoreUIProvider>
    </ConfigProvider>
  );
};
