import { Children, cloneElement, isValidElement, use, useMemo } from 'react';
import { Box, CircularProgress, Divider, Typography } from '@mui/material';
import type { BoxProps, Theme } from '@mui/material';
import { useCreation, useMemoizedFn, useRequest } from 'ahooks';
import pWaitFor from 'p-wait-for';
import Helmet from 'react-helmet';

import { SessionContext } from '@arcblock/did-connect-react/lib/Session';
import Tabs from '@arcblock/ux/lib/Tabs';
import Empty from '@arcblock/ux/lib/Empty';
import Button from '@arcblock/ux/lib/Button';
import Result from '@arcblock/ux/lib/Result';
import { useConfirm } from '@arcblock/ux/lib/Dialog';
import { translate } from '@arcblock/ux/lib/Locale/util';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary';
import { styled } from '@arcblock/ux/lib/Theme';
import cloneDeep from 'lodash/cloneDeep';
import { getQuery, withQuery, joinURL, withoutTrailingSlash } from 'ufo';
import type { AxiosError } from 'axios';
import type { UserPublicInfo } from '@blocklet/js-sdk';
import { isSupportFollow } from '@arcblock/ux/lib/Util';

import { PROFILE_URL } from '@arcblock/ux/lib/Util/constant';
import Footer from '../../Footer';
import Header from '../../Header';
import { translations } from '../libs/locales';
import { UserBasicInfo } from './user-info';
import type { SessionContext as TSessionContext, User, UserCenterTab } from '../../@types';
// @ts-ignore
import { formatBlockletInfo, getLink, getLocalizedNavigation } from '../../blocklets';
import Passport from './passport';
import Settings from './settings';
import { client } from '../../libs/client';
import useMobile from '../../hooks/use-mobile';
import { ConfigUserSpaceProvider } from '../../contexts/config-user-space';
import DidSpace from './storage';
import Nft from './nft';
import { UserFollowersProvider } from '../../contexts/user-followers';
import Fallback from './fallback';

const nftsLink = joinURL(PROFILE_URL, '/nfts');
const settingsLink = joinURL(PROFILE_URL, '/settings');
const didSpacesLink = joinURL(PROFILE_URL, '/did-spaces');
const userFollowersLink = joinURL(PROFILE_URL, '/user-followers');

const hasSystemMenusInjected = (menus: Array<any>) => {
  return menus.some(
    (menu: any) =>
      ['/userCenter/nfts', '/userCenter/user-followers', '/userCenter/settings', '/userCenter/did-spaces'].includes(
        menu.id
      ) || [nftsLink, settingsLink, didSpacesLink, userFollowersLink].includes(menu.link)
  );
};

interface NavigationTabProps {
  label: string;
  protected: boolean;
  isPrivate: boolean;
  value: string;
  url: string;
  [key: string]: any;
}

const Main = styled(Box)(({ theme }) => ({
  flex: 1,
  boxSizing: 'border-box',
  padding: '0 16px',
  width: '100%',
  maxWidth: 1600,
  margin: '0 auto',
  display: 'flex',
  alignItems: 'stretch',
  gap: 2.5,
  flexDirection: 'column',
  [theme.breakpoints.up('md')]: {
    flexDirection: 'row',
  },
}));

const ContentWrapper = styled(Box)(({ theme }) => ({
  overflow: 'hidden',
  flex: 'revert',
  [theme.breakpoints.up('md')]: {
    flex: 1,
  },
  '@media (min-width: 960px) and (max-width: 1050px)': {
    '& .user-center-tabs': {
      maxWidth: '500px',
    },
  },
}));

export default function UserCenter({
  children,
  notLoginContent = null,
  currentTab,
  contentProps = {},
  disableAutoRedirect = false,
  hideFooter = false,
  headerProps = {},
  footerProps = {},
  userDid = undefined,
  stickySidebar = false,
  embed = false,
  onlyProfile = false, // 只显示 profile 页面，用于 ArcSphere 只需要显示 Profile 的内容
  onDestroySelf = undefined,
}: {
  readonly children: any;
  readonly notLoginContent?: any;
  readonly currentTab: string;
  readonly contentProps?: BoxProps;
  readonly disableAutoRedirect?: boolean;
  readonly autoPopupSetting?: boolean;
  readonly hideFooter?: boolean;
  // FIXME: @zhanghan 将 header 和 footer 改为 ts 后，去掉这个 any
  readonly headerProps?: any;
  readonly footerProps?: any;
  readonly userDid?: string;
  readonly stickySidebar?: boolean;
  readonly embed?: boolean;
  readonly onlyProfile?: boolean;
  readonly onDestroySelf?: () => void;
}) {
  const { locale, defaultLocale } = useLocaleContext();
  const isMobile = useMobile({ key: 'md' });
  const t = useMemoizedFn((key, data = {}) => {
    return translate(translations, key, locale, 'en', data);
  });
  const sessionCtx: TSessionContext = use(SessionContext);
  const session = sessionCtx?.session;

  const currentDid = useCreation(() => {
    if (userDid) {
      return userDid;
    }

    const currentUrl = window.location.href;
    const query = getQuery(currentUrl);
    if (query?.did) {
      if (Array.isArray(query.did)) {
        return query.did[0];
      }
      return query.did;
    }
    return session?.user?.did;
  }, [session?.user?.did, userDid]);

  const isMyself = useCreation(() => {
    if (session?.user) {
      return currentDid === session?.user?.did;
    }
    return false;
  }, [currentDid, session?.user?.did]);

  const isShowSocialActions = useMemo((): boolean => {
    return isSupportFollow();
  }, []);

  const userState = useRequest<UserPublicInfo | User | undefined, []>(
    // eslint-disable-next-line consistent-return
    async () => {
      await pWaitFor(() => session?.initialized);
      if (isMyself) {
        return session.user as User;
      }
      if (currentDid) {
        return client.user.getUserPublicInfo({ did: currentDid });
      }
    },
    {
      refreshDeps: [currentDid, isMyself, session?.initialized, session?.user],
    }
  );

  const onRefreshUser = useMemoizedFn(() => {
    if (isMyself) {
      return session.refresh();
    }
    return userState.refresh();
  });

  const privacyState = useRequest(
    async () => {
      if (userState.data && currentTab) {
        const config = await client.user.getUserPrivacyConfig({ did: currentDid as string });
        return config;
      }
      return null;
    },
    {
      refreshDeps: [currentDid, userState.data, currentTab],
      loadingDelay: 300,
    }
  );

  const { confirmHolder } = useConfirm({
    fullScreen: isMobile,
    sx: {
      '.MuiDialog-paper': {
        borderRadius: 1,
        maxWidth: 1200,
      },
      '.ux-dialog_title': {
        fontWeight: 600,
      },
      '.ux-dialog_closeButton': {
        p: 1,
      },
      '.MuiDialogActions-root': {
        display: {
          xs: 'none',
          md: 'flex',
        },
      },
    },
  });

  const formattedBlocklet = useCreation(() => {
    const blocklet = cloneDeep(window.blocklet);
    try {
      return formatBlockletInfo(blocklet);
    } catch (e) {
      console.error('Failed to format blocklet info', e, blocklet);
      return blocklet;
    }
  }, []);

  const defaultTabs = useCreation((): NavigationTabProps[] => {
    const nftTab = {
      label: t('common.nft'),
      protected: false,
      isPrivate: false, // true: 隐私数据，仅自己可见
      value: nftsLink,
      url: getLink(nftsLink, locale, defaultLocale),
    };
    const userFollowersTab = {
      label: t('userFollowers'),
      protected: false,
      isPrivate: false,
      value: userFollowersLink,
      url: getLink(userFollowersLink, locale, defaultLocale),
    };
    let tabs: NavigationTabProps[] = isShowSocialActions ? [nftTab, userFollowersTab] : [nftTab];
    if (isMyself) {
      const restTabs = [
        nftTab,
        {
          label: t('common.setting'),
          protected: true,
          isPrivate: true,
          value: settingsLink,
          url: getLink(settingsLink, locale, defaultLocale),
        },
        {
          label: t('storageManagement'),
          protected: true,
          isPrivate: true,
          value: didSpacesLink,
          url: getLink(didSpacesLink, locale, defaultLocale),
        },
      ];
      tabs = isShowSocialActions ? [...restTabs, userFollowersTab] : restTabs;
    }
    return tabs;
  }, [isMyself, locale, isShowSocialActions]);

  const userCenterTabs = useCreation<UserCenterTab[]>(() => {
    const menus = formattedBlocklet?.navigation?.userCenter || [];
    const hasSystemMenus = hasSystemMenusInjected(menus);
    const localizedMenus = getLocalizedNavigation({ navigation: menus, locale, defaultLocale }) || [];
    const allMenus = localizedMenus.concat(hasSystemMenus ? [] : defaultTabs);
    return allMenus
      .map((x: any) => {
        const value = x.value ?? x._rawLink ?? x.link ?? x.url;

        return {
          value,
          label: x.title || x.label,
          url: x.link || x.url,
          protected: privacyState?.data?.[value] ?? false,
          isPrivate: x.isPrivate || x.private || (x?._rawLink?.includes('/customer') ?? false), // FIXME: HACK: 隐藏 /customer 菜单, 需要一个通用的解决方案，在嵌入的时候就决定是否是私有的
          followersOnly: x.component === 'did-comments', // 是否开启仅粉丝可查看的功能，目前只对 discuss kit 开启
          // icon: x.icon,
        };
      })
      .filter((x: any) => isMyself || !x.isPrivate);
  }, [formattedBlocklet, userState.data, privacyState?.data, locale, defaultTabs, isMyself]);

  const currentActiveTab = useCreation(() => {
    return userCenterTabs.find((x) => withoutTrailingSlash(x.value) === withoutTrailingSlash(currentTab));
  }, [userCenterTabs]);

  const htmlTitle = useCreation(() => {
    const blockletName = window.blocklet?.appName;
    const titleGroup = [currentActiveTab?.label, t('userCenter.title')].filter(Boolean);
    const title = titleGroup.join('-');
    if (blockletName) {
      return `${title} | ${blockletName}`;
    }
    return title;
  }, [currentActiveTab, t]);

  // 辅助函数：给 children 注入 userCenterTabs 属性
  const renderChildrenWithProps = useMemoizedFn((childrenToRender: any) => {
    if (!childrenToRender) return childrenToRender;

    // 如果 children 是单个 React 元素，克隆并注入 props
    if (isValidElement(childrenToRender)) {
      return cloneElement(childrenToRender as any, {
        ...(childrenToRender.props || {}),
        userCenterTabs,
      });
    }

    // 如果 children 是数组，遍历每个元素并注入 props
    return Children.map(childrenToRender, (child) => {
      if (isValidElement(child)) {
        return cloneElement(child as any, {
          ...(child.props || {}),
          userCenterTabs,
        });
      }
      return child;
    });
  });

  const handleChangeTab = useMemoizedFn((value) => {
    const findTab = userCenterTabs.find((x) => x.value === value);
    if (findTab) {
      // 这里是安全的
      window.location.href = withQuery(findTab.url, {
        did: isMyself ? undefined : currentDid,
      });
    }
  });

  const settingContent = useCreation(() => {
    return (
      <Settings
        user={userState.data as User}
        settings={{ userCenterTabs }}
        onSave={async (type: 'privacy' | 'profile') => {
          if (type === 'privacy') {
            await privacyState.runAsync();
            return privacyState.data;
          }
          if (type === 'profile') {
            await session.refresh();
          }
          return null;
        }}
        isMobile={isMobile}
        onDestroySelf={onDestroySelf}
      />
    );
  }, [userState.data, userCenterTabs, privacyState.data, privacyState.runAsync]);

  const isSettingTab = useCreation(() => {
    return currentActiveTab && currentActiveTab?.value === settingsLink;
  }, [currentActiveTab]);

  const isNftsTab = useCreation(() => {
    return (
      (currentActiveTab && currentActiveTab?.value === joinURL(PROFILE_URL, '/profile')) ||
      currentActiveTab?.value === nftsLink
    );
  }, [currentActiveTab]);

  const isDidSpaceTab = useCreation(() => {
    return currentActiveTab && currentActiveTab?.value === didSpacesLink;
  }, [currentActiveTab]);

  const oauth = session.useOAuth();
  const passkey = session.usePasskey();
  const handleSwitchPassport = useMemoizedFn(() => {
    if (session?.user?.sourceProvider === 'passkey') {
      passkey.switchPassport(session.user);
    } else if (['google', 'apple', 'email', 'github'].includes(session?.user?.sourceProvider ?? '')) {
      oauth.switchOAuthPassport(session.user);
    } else if (session) {
      session.switchPassport();
    }
  });

  const renderDefaultTab = useCreation(() => {
    if (isNftsTab) {
      return (
        <Box
          sx={{
            display: 'flex',
            flexDirection: 'column',
            gap: 2.5,
          }}>
          {isMyself ? (
            <Box sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 1.5, p: 2 }}>
              <Typography
                sx={{
                  color: 'text.primary',
                  fontWeight: 600,
                  mb: 2.5,
                }}>
                {t('passport')}
              </Typography>
              <Passport user={userState.data as User} />
            </Box>
          ) : null}
          <Nft user={userState.data as User} />
        </Box>
      );
    }
    if (isSettingTab && isMyself) {
      return settingContent;
    }
    if (isDidSpaceTab && isMyself) {
      return (
        <ConfigUserSpaceProvider>
          <DidSpace />
        </ConfigUserSpaceProvider>
      );
    }
    return null;
  }, [isSettingTab, isNftsTab, userState, isMyself, stickySidebar, settingContent]);

  const emptyContent = useCreation(() => {
    return (
      <Box
        sx={{
          display: {
            xs: isMyself ? 'none' : 'block',
            md: 'block',
          },
          py: 3,
        }}>
        <Empty>{t('emptyContent')}</Empty>
      </Box>
    );
  }, [isMyself, locale]);

  const tabContent = useCreation(() => {
    if (!privacyState.data || privacyState.loading) {
      return (
        <Box
          sx={{
            height: '100%',
            minWidth: '160px',
            minHeight: '160px',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            flex: 1,
          }}>
          <CircularProgress />
        </Box>
      );
    }

    return (
      <Box sx={{ flex: 1 }}>
        <Fallback
          isSupportFollow={isShowSocialActions}
          currentActiveTab={currentActiveTab as UserCenterTab}
          isMyself={isMyself}>
          {children ? <Box {...contentProps}>{renderChildrenWithProps(children)}</Box> : renderDefaultTab}
        </Fallback>
      </Box>
    );
  }, [privacyState, currentActiveTab, isMyself, children, contentProps, renderDefaultTab, locale]);

  const content = useCreation(() => {
    if (userState.loading || session.loading) {
      return null;
    }

    if (userState.error) {
      const errorStatus = (userState.error as AxiosError<{ error: string }>)?.response?.status;
      if (errorStatus === 404) {
        return (
          <Box sx={{ width: '100%' }}>
            <Result status={404} description={t('noUserFound')} />
          </Box>
        );
      }

      const errorMessage =
        (userState.error as AxiosError<{ error: string }>).response?.data?.error ||
        userState.error.message ||
        'error occurred';

      const formatError = {
        message: errorMessage,
      };
      return (
        <Box sx={{ width: '100%' }}>
          <ErrorFallback error={formatError} />
        </Box>
      );
    }

    if (!currentDid && !userState.data) {
      if (notLoginContent) {
        return notLoginContent;
      }
      return (
        <Box sx={{ width: '100%' }}>
          <Box
            sx={{
              display: 'flex',
              flexDirection: 'column',
              justifyContent: 'center',
              alignItems: 'center',
              gap: 1,
            }}>
            <Empty>{t('viewAfterLogin')}</Empty>
            <Button size="small" variant="contained" onClick={() => session.login()}>
              {t('loginNow')}
            </Button>
          </Box>
        </Box>
      );
    }

    if (currentDid && !userState.data && !userState.loading) {
      return (
        <Empty style={{ width: '100%', paddingTop: 16 }}>
          <Box sx={{ textAlign: 'center', width: '100%' }}>
            <Typography variant="body1" sx={{ fontSize: 18, fontWeight: 500 }}>
              {t('userNotFound')}
            </Typography>
            <Typography variant="body1" color="text.secondary">
              {t('userNotFoundDescription')}
            </Typography>
          </Box>
        </Empty>
      );
    }

    // 嵌入时，只显示 tabContent
    if (embed) {
      return (
        <ContentWrapper>
          {userCenterTabs.length > 0 && currentTab ? (
            <Box
              sx={{
                display: isMobile ? 'block' : 'flex',
                height: '100%',
                overflow: 'auto',
                padding: '1px',
              }}>
              {tabContent}
            </Box>
          ) : null}
          {userCenterTabs.length === 0 && emptyContent}
        </ContentWrapper>
      );
    }

    if (onlyProfile) {
      return (
        <ContentWrapper display="flex" flexDirection={isMobile ? 'column' : 'row'}>
          <UserBasicInfo
            isMobile={isMobile}
            order={isMobile ? 1 : 'unset'}
            isMyself={isMyself}
            switchPassport={handleSwitchPassport}
            switchProfile={session.switchProfile}
            user={userState.data as User}
            showFullDid={false}
            onlyProfile={onlyProfile}
            refreshProfile={onRefreshUser}
            isShowSocialActions={isShowSocialActions}
            sx={{
              padding: !isMobile ? '40px 24px 24px 40px' : '16px 0 0 0',
              ...(!isMobile ? { width: 320, maxWidth: 320, flexShrink: 0 } : {}),
              boxSizing: 'content-box',
            }}
          />
        </ContentWrapper>
      );
    }

    return (
      <ContentWrapper display="flex" flexDirection={isMobile ? 'column' : 'row'}>
        <Box
          className="user-center-tabs"
          sx={{
            flex: '1',
            order: isMobile ? 2 : 'unset',
            width: !isMobile ? 'calc(100% - 424px)' : 'unset',
          }}>
          {userCenterTabs.length > 0 && currentTab ? (
            <Box
              sx={{
                display: 'flex',
                flexDirection: 'column',
                height: '100%',
                overflow: 'auto',
                padding: '1px',
              }}>
              <Tabs
                orientation="horizontal"
                variant="line"
                tabs={userCenterTabs}
                current={currentActiveTab?.value ?? currentTab}
                onChange={handleChangeTab}
                enableTabClick
                sx={{
                  mb: (theme: Theme) => `${theme.spacing(3)} !important`,
                  '.MuiTabs-flexContainer': {
                    gap: 3,
                    '.MuiButtonBase-root': {
                      padding: isMobile ? '16px 4px' : '32px 4px 16px 4px',
                      fontSize: 16,
                    },
                    '.MuiTab-root': {
                      display: 'block',
                      textAlign: 'left',
                      alignItems: 'flex-start',
                      justifyContent: 'flex-start',
                      fontWeight: 400,
                      mr: 0,
                    },
                  },
                  '.MuiTabs-indicator': {
                    zIndex: 2,
                  },
                  '.MuiTabs-scroller': {
                    '&:after': {
                      content: '""',
                      display: 'block',
                      position: 'sticky',
                      left: 0,
                      zIndex: 1,
                      width: '100%',
                      height: '1px',
                      backgroundColor: 'divider',
                    },
                  },
                }}
              />
              {tabContent}
            </Box>
          ) : null}
          {userCenterTabs.length === 0 && emptyContent}
        </Box>
        {!isMobile && <Divider orientation="vertical" sx={{ ml: 5 }} />}
        <UserBasicInfo
          isMobile={isMobile}
          order={isMobile ? 1 : 'unset'}
          isMyself={isMyself}
          switchPassport={handleSwitchPassport}
          switchProfile={session.switchProfile}
          user={userState.data as User}
          refreshProfile={onRefreshUser}
          showFullDid={false}
          isShowSocialActions={isShowSocialActions}
          sx={{
            padding: !isMobile ? '40px 24px 24px 40px' : '16px 0 0 0',
            ...(!isMobile ? { width: 320, maxWidth: 320, flexShrink: 0 } : {}),
            boxSizing: 'content-box',
          }}
        />
      </ContentWrapper>
    );
  }, [
    userState,
    userCenterTabs,
    isMyself,
    currentActiveTab,
    privacyState,
    currentTab,
    stickySidebar,
    renderDefaultTab,
  ]);

  // 如果当前URL指向的是 private tab需要重定向
  const isPrivateActive = useCreation(() => {
    if (isMyself) {
      return false;
    }
    return currentActiveTab?.isPrivate;
  }, [isMyself, currentActiveTab]);

  // 判断是否需要重定向到第一个可用的标签页
  const shouldRedirect = useCreation(() => {
    // 非 Profile 模式下才考虑重定向
    if (onlyProfile) {
      return false;
    }

    // 以下任一条件满足时需要重定向:
    // 1. 自动重定向开启且当前无激活标签但有可用标签
    const noActiveTabButHasTabs = !disableAutoRedirect && !currentTab && userCenterTabs?.length > 0;
    // 2. 当前标签页不存在
    const invalidCurrentTab = !currentActiveTab;
    // 3. 当前是私有标签页但用户在查看他人信息
    const accessingPrivateTab = isPrivateActive;

    return noActiveTabButHasTabs || invalidCurrentTab || accessingPrivateTab;
  }, [disableAutoRedirect, currentTab, userCenterTabs, currentActiveTab, isPrivateActive, onlyProfile]);

  if (shouldRedirect) {
    // 获取第一个可用的标签页URL
    const firstUserCenterUrl = userCenterTabs[0]?.url;
    const firstTab = userCenterTabs.find((x) => x.value === firstUserCenterUrl);
    // 如果存在非私有的第一个标签页，则重定向
    if (firstUserCenterUrl && !firstTab?.isPrivate) {
      window.location.replace(
        withQuery(firstUserCenterUrl, {
          did: isMyself ? undefined : currentDid,
        })
      );
    }
    return null;
  }

  // 嵌入其它页面内时，只展示 content
  if (embed || onlyProfile) {
    return (
      <Box>
        {/* 在 Arcsphere 中，需要渲染 header 用于注入某些 bridge 方法，设置为隐藏状态 */}
        <Helmet>
          <title>{htmlTitle}</title>
        </Helmet>
        <Header style={{ display: 'none' }} />
        <Main>
          <UserFollowersProvider isMySelf={isMyself} userDid={userState.data?.did ?? ''}>
            {content}
          </UserFollowersProvider>
          {confirmHolder}
        </Main>
      </Box>
    );
  }

  return (
    <Box
      sx={{
        minHeight: '100vh',
        display: 'flex',
        flexDirection: 'column',
      }}>
      <Helmet>
        <title>{htmlTitle}</title>
      </Helmet>
      <Header bordered {...headerProps} maxWidth="100%" />
      <Main>
        <UserFollowersProvider isMySelf={isMyself} userDid={userState.data?.did ?? ''}>
          {content}
        </UserFollowersProvider>
        {confirmHolder}
      </Main>
      {hideFooter ? null : (
        <Footer
          bordered
          {...footerProps}
          sx={{
            '.MuiContainer-root': {
              maxWidth: 1600,
            },
          }}
        />
      )}
    </Box>
  );
}
