import { ElementType, useEffect, useRef } from 'react';
import { useCreation, useMemoizedFn, useReactive } from 'ahooks';
import bridge from '@arcblock/bridge';
import {
  Box,
  type BoxProps,
  ClickAwayListener,
  Divider,
  Fade,
  IconButton,
  MenuItem,
  MenuList,
  Paper,
  Popper,
} from '@mui/material';
import { Icon, type IconifyIcon } from '@iconify/react';
import PersonOutlineRoundedIcon from '@iconify-icons/material-symbols/person-outline-rounded';
import FilterVintageOutlineRoundedIcon from '@iconify-icons/material-symbols/filter-vintage-outline-rounded';
import AccountCircleOffOutlineRoundedIcon from '@iconify-icons/material-symbols/account-circle-off-outline-rounded';
import InviteIcon from '@iconify-icons/material-symbols/featured-seasonal-and-gifts-rounded';
import Copy from 'copy-to-clipboard';
import noop from 'lodash/noop';

import Toast from '../../Toast';
import DidAvatar from '../../Avatar';
import { getUserAvatar } from '../../Util';
import UserInfo from './user-info';
import { DASHBOARD_URL, PROFILE_URL } from '../../Util/constant';
import SessionPermission from '../../SessionPermission';
import { translations } from '../libs/translation';
import { translate } from '../../Locale/util';
import type { Locale, Session } from '../../type';
import DidSpace from './did-space';
import { mergeSx } from '../../Util/style';
import { createDebug } from '../../Util/logger';
import { GA_LAST_ROLE } from '../../withTracker/constant';

const getInviteLink = (inviter: string) => {
  const url = new URL(window.location.href);
  url.searchParams.set('inviter', inviter);
  return url.toString();
};

const debug = createDebug('did-connect');

export interface LoggedInProps extends Omit<BoxProps, 'onClick' | 'onMouseEnter' | 'onMouseLeave'> {
  session: Session;
  onBindWallet?: () => void;
  isBlocklet?: true | false;
  locale?: Locale;
  size?: number;
  popperType?: 'hover' | 'click';
}

export default function LoggedIn({
  session,
  onBindWallet = noop,
  isBlocklet = true,
  locale = 'en',
  size = 24,
  popperType = 'click',
  sx,
  ...rest
}: LoggedInProps) {
  const t = useMemoizedFn((key, data = {}) => {
    return translate(translations, key, locale, 'en', data);
  });
  const isInviteEnabled = useCreation(() => {
    return !!globalThis?.blocklet?.settings?.invite?.enabled;
  }, []);
  const popperAnchorRef = useRef(null);
  const currentState = useReactive({
    open: false,
  });
  const onTogglePopper = useMemoizedFn((value = !currentState.open) => {
    currentState.open = value;
  });
  const handleEventProps =
    popperType === 'hover'
      ? { onMouseEnter: () => onTogglePopper(true), onMouseLeave: () => onTogglePopper(false) }
      : { onClick: () => onTogglePopper() };

  // base64 img maybe have some blank char, need encodeURIComponent to transform it
  const avatar = getUserAvatar(session.user?.avatar?.replace(/\s/g, encodeURIComponent(' ')));

  // FIXME: @zhanghan this should be refactored into SessionContext
  const oauth = session.useOAuth();
  const passkey = typeof session.usePasskey === 'function' ? session.usePasskey() : null;
  const handleSwitchPassport = useMemoizedFn(({ inArcSphere = false } = {}) => {
    localStorage.setItem(GA_LAST_ROLE, session?.user?.role);
    const extraParams: Record<string, any> = {};
    if (inArcSphere) {
      if (session?.user?.sourceAppPid) {
        extraParams.sourceAppPid = session.user.sourceAppPid;
      }
    }
    onTogglePopper(false);
    if (session?.user?.sourceProvider === 'passkey') {
      passkey.switchPassport(session.user);
    } else if (['google', 'apple', 'email', 'github'].includes(session?.user?.sourceProvider)) {
      oauth.switchOAuthPassport(session.user);
    } else {
      session.switchPassport(noop, extraParams);
    }
  });

  const handleSwitchAccount = useMemoizedFn(({ userSession, inArcSphere = false } = {}) => {
    return new Promise<void>((resolve) => {
      const extraParams: Record<string, any> = {};
      if (inArcSphere) {
        if (session.user.sourceAppPid) {
          extraParams.sourceAppPid = session.user.sourceAppPid;
        }
      }
      const options: Record<string, any> = {};
      if (!userSession) {
        onTogglePopper(false);
        options.showQuickConnect = false;
      } else {
        options.userSession = userSession;
      }
      session.switchDid(
        () => {
          onTogglePopper(false);
          resolve();
        },
        extraParams,
        options
      );
    });
  });
  const handleSwitchProfile = useMemoizedFn(({ inArcSphere = false } = {}) => {
    const extraParams: Record<string, any> = {};
    if (inArcSphere) {
      if (session.user.sourceAppPid) {
        extraParams.sourceAppPid = session.user.sourceAppPid;
      }
    }
    onTogglePopper(false);
    session.switchProfile(noop, extraParams);
  });
  const onLogout = useMemoizedFn(() => {
    onTogglePopper(false);
    session.logout();
  });

  const handleBindWallet = useMemoizedFn(() => {
    onTogglePopper(false);
    session.bindWallet(onBindWallet);
  });

  const handleOpenInvite = useMemoizedFn(() => {
    onTogglePopper(false);
    const link = getInviteLink(session.user.did);
    Copy(link);
    Toast.success(t('inviteCopied'));
  });

  useEffect(() => {
    bridge.registerBlocklet('callSwitchPassport', () => {
      debug('bridge registerBlocklet: callSwitchPassport');
      handleSwitchPassport({ inArcSphere: true });
    });
    bridge.registerBlocklet('callSwitchDid', () => {
      debug('bridge registerBlocklet: callSwitchDid');
      handleSwitchAccount({ inArcSphere: true });
    });
    bridge.registerBlocklet('callSwitchProfile', () => {
      debug('bridge registerBlocklet: callSwitchProfile');
      handleSwitchProfile({ inArcSphere: true });
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <Box
      sx={mergeSx(
        {
          display: 'inline-flex',
          alignItems: 'center',
          justifyContent: 'center',
        },
        // @ts-ignore
        sx
      )}
      {...rest}>
      <IconButton
        ref={popperAnchorRef}
        size="medium"
        data-cy="sessionManager-logout-popup"
        className="arc-session-user-logged-in"
        aria-label="User info button"
        {...handleEventProps}>
        <DidAvatar variant="circle" did={session.user.did} src={avatar} size={size} shape="circle" />
      </IconButton>

      <Popper
        open={currentState.open}
        anchorEl={popperAnchorRef.current}
        transition
        placement="bottom-end"
        sx={{
          zIndex: 1600,
        }}>
        {({ TransitionProps }) => (
          <ClickAwayListener
            onClickAway={(e) => {
              e.preventDefault();
              e.stopPropagation();
              onTogglePopper(false);
            }}>
            <Fade {...TransitionProps} timeout={350}>
              <Paper
                variant="outlined"
                sx={{
                  borderRadius: 1.5,
                  width: 350,
                  maxWidth: '90vw',
                }}>
                <UserInfo
                  locale={locale}
                  isBlocklet={isBlocklet}
                  session={session}
                  onSwitchPassport={handleSwitchPassport}
                  onSwitchAccount={handleSwitchAccount}
                  onSwitchProfile={handleSwitchProfile}
                  onBindWallet={handleBindWallet}
                />
                <Divider sx={{ m: '0 !important' }} />
                <MenuList sx={{ p: 0 }}>
                  {isBlocklet ? (
                    <>
                      <SessionPermission session={session}>
                        <SessionMenuItem
                          icon={FilterVintageOutlineRoundedIcon}
                          title={t('dashboard')}
                          component="a"
                          href={DASHBOARD_URL}
                          sx={{ display: 'block', textDecoration: 'none', color: 'inherit' }}
                        />
                      </SessionPermission>
                      <SessionMenuItem
                        icon={PersonOutlineRoundedIcon}
                        title={t('profile')}
                        component="a"
                        href={PROFILE_URL}
                        sx={{ display: 'block', textDecoration: 'none', color: 'inherit' }}
                      />
                      {isInviteEnabled && (
                        <SessionMenuItem
                          icon={InviteIcon}
                          title={t('invite')}
                          component="div"
                          onClick={handleOpenInvite}
                          sx={{ display: 'block', color: 'inherit' }}
                        />
                      )}
                      <Divider sx={{ m: '0 !important' }} />
                      <DidSpace session={session} locale={locale} />
                    </>
                  ) : null}
                  <SessionMenuItem
                    icon={AccountCircleOffOutlineRoundedIcon}
                    title={t('logout')}
                    component="div"
                    sx={{ color: 'error.main' }}
                    onClick={onLogout}
                    data-cy="sessionManager-logout-trigger"
                  />
                </MenuList>
              </Paper>
            </Fade>
          </ClickAwayListener>
        )}
      </Popper>
    </Box>
  );
}

interface SessionMenuItemProps {
  icon: IconifyIcon | string;
  title: string;
}

// prop component is required
function SessionMenuItem<C extends ElementType>({
  icon,
  title,
  ...rest
}: SessionMenuItemProps & BoxProps<C, { component: C }>) {
  return (
    <Box {...rest} sx={{ p: 0.5, ...rest?.sx }}>
      <MenuItem
        sx={{
          display: 'flex',
          gap: 1,
          alignItems: 'center',
          borderRadius: 1,
          '&:hover': {
            backgroundColor: 'action.hover',
          },
          py: 1,
        }}>
        <Icon icon={icon} fontSize={24} />
        {title}
      </MenuItem>
    </Box>
  );
}
