import 'iconify-icon';

/* eslint-disable no-shadow */
import { useMemo, useLayoutEffect, use } from 'react';
import PropTypes from 'prop-types';
import { SessionContext } from '@arcblock/did-connect-react/lib/Session';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import UxImg from '@arcblock/ux/lib/Img';
import UxDashboard from '@arcblock/ux/lib/Layout/dashboard';
import useBlockletLogo from '@arcblock/ux/lib/hooks/use-blocklet-logo';
import { BlockletMetaProps, SessionManagerProps } from '../types';
import { mapRecursive, flatRecursive, matchPaths } from '../utils';
import { publicPath, formatBlockletInfo, getLocalizedNavigation, filterNavByRole } from '../blocklets';
import HeaderAddons from '../common/header-addons';
import { useWalletHiddenTopbar } from '../common/wallet-hidden-topbar';
import { AppHeader, AppBadge, AppInfoProvider, useAppInfo } from './app-shell';

/**
 * 专门用于 (composable) blocklet 的 Dashboard 组件, 解析 blocklet meta 中 section 为 dashboard 的 navigation 数据, 渲染一个 UX Dashboard
 */
function Dashboard({
  meta = undefined,
  fallbackUrl = publicPath,
  invalidPathFallback = null,
  headerAddons = undefined,
  sessionManagerProps = {
    showRole: true,
    // dashboard 默认退出登录行为: 跳转到 (root) blocklet 首页
    onLogout: () => {
      // 这里是安全的
      window.location.href = publicPath;
    },
  },
  links = [],
  showDomainWarningDialog = true,
  appPath = undefined,
  appTab = undefined,
  onAppTabChange = undefined,
  children = undefined,
  ...rest
}) {
  useWalletHiddenTopbar();
  const sessionCtx = use(SessionContext);
  const user = sessionCtx?.session?.user;
  const userRole = user?.role;
  const { locale, defaultLocale } = useLocaleContext() || {};
  const formattedBlocklet = useMemo(() => {
    const blocklet = Object.assign({}, window.blocklet, meta);
    try {
      return formatBlockletInfo(blocklet);
    } catch (e) {
      console.error('Failed to format blocklet info', e, blocklet);
      return blocklet;
    }
  }, [meta]);
  const { localizedNav, flattened, matchedIndex } = useMemo(() => {
    // eslint-disable-next-line @typescript-eslint/no-shadow
    let localizedNav =
      getLocalizedNavigation({
        navigation: formattedBlocklet?.navigation?.dashboard,
        locale,
        defaultLocale,
      }) || [];
    // 根据 role 筛选 nav 数据
    localizedNav = filterNavByRole(localizedNav, userRole);
    // 将 nav 数据处理成 ux dashboard 需要的格式
    localizedNav = mapRecursive(
      localizedNav,
      (item) => {
        let icon = null;

        if (item.icon) {
          if (item.icon.startsWith('http') || item.icon.startsWith('data:')) {
            icon = <UxImg src={item.icon} />;
          } else {
            icon = <iconify-icon height="100%" width="100%" icon={item.icon} />;
          }
        }

        return {
          id: item.id,
          title: item.title,
          url: item.link,
          icon,
          // https://github.com/ArcBlock/ux/issues/755#issuecomment-1208692620
          external: true,
          children: item.items,
        };
      },
      'items'
    );
    // 展平后使用 matchPaths 检测 link#active 状态
    // eslint-disable-next-line @typescript-eslint/no-shadow
    const flattened = flatRecursive(localizedNav).filter((item) => !!item.url);
    // eslint-disable-next-line @typescript-eslint/no-shadow
    const matchedIndex = matchPaths(flattened.map((item) => item.url));
    if (matchedIndex !== -1) {
      flattened[matchedIndex].active = true;
    }
    return { localizedNav, flattened, matchedIndex };
  }, [formattedBlocklet, locale, defaultLocale, userRole]);

  const allLinks = typeof links === 'function' ? links(localizedNav) : [...localizedNav, ...links];
  const appLogo = useBlockletLogo({
    meta,
  });

  // 页面初始化时, 如果当前用户没有权限访问任何导航菜单 (比如登录时未提供 VC 导致无权限), 则跳转到 fallbackUrl
  // 未认证 (user 为空) 时不做处理, 这种情况的页面跳转逻辑一般由应用自行处理
  useLayoutEffect(() => {
    if (!!user && !flattened?.length && fallbackUrl) {
      // 这里是安全的
      window.location.href = fallbackUrl;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fallbackUrl]);

  // 导航菜单变动且存在可用菜单但无匹配项时 (如切换 passport), 跳转到首个菜单项
  useLayoutEffect(() => {
    if (!!user && !!flattened?.length && matchedIndex === -1) {
      if (invalidPathFallback) {
        invalidPathFallback();
      } else {
        // FIXME: @zhanghan 暂时取消跳转首个 url 的行为
        // window.location.href = flattened[0]?.url || publicPath;
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [invalidPathFallback, flattened, matchedIndex]);

  if (!formattedBlocklet.appName) {
    return null;
  }
  const { appName } = formattedBlocklet;
  // eslint-disable-next-line @typescript-eslint/naming-convention
  const _headerAddons = (
    <HeaderAddons
      formattedBlocklet={formattedBlocklet}
      addons={headerAddons}
      sessionManagerProps={sessionManagerProps}
      showDomainWarningDialog={showDomainWarningDialog}
    />
  );

  return (
    <UxDashboard
      title={appName}
      fullWidth
      sidebarWidth={128}
      legacy={false}
      links={allLinks}
      {...rest}
      headerProps={{
        homeLink: publicPath,
        logo: <img src={appLogo} alt="logo" />,
        addons: _headerAddons,
        ...rest.headerProps,
      }}>
      <AppInfoProvider path={appPath} currentTab={appTab} meta={meta}>
        <AppHeader onTabChange={onAppTabChange} />
        {children}
      </AppInfoProvider>
    </UxDashboard>
  );
}

Dashboard.propTypes = {
  meta: BlockletMetaProps,
  // 如果当前用户没有权限访问任何导航菜单, 则自动跳转到 fallbackUrl, 默认值为 publicPath, 设置为 null 表示禁用自动跳转
  fallbackUrl: PropTypes.string,
  // 当前路径未匹配任何 nav links 时的 fallback, 默认行为跳转到首个可用的 nav link
  invalidPathFallback: PropTypes.func,
  headerAddons: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
  sessionManagerProps: SessionManagerProps,
  links: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
  showDomainWarningDialog: PropTypes.bool,
  appPath: PropTypes.string,
  appTab: PropTypes.string,
  onAppTabChange: PropTypes.func,
  children: PropTypes.node,
};

export { AppHeader, AppBadge, AppInfoProvider, useAppInfo };
export default Dashboard;
