// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import type { Key, ReactNode } from 'react';
import React, { useEffect, useState } from 'react';
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'react-aria-components';
import classNames from 'classnames';
import { usePopper } from 'react-popper';
import { createPortal } from 'react-dom';
import { Avatar, AvatarSize } from './Avatar';
import type { LocalizerType, ThemeType } from '../types/Util';
import type { ConversationType } from '../state/ducks/conversations';
import type { BadgeType } from '../badges/types';
import { AvatarPopup } from './AvatarPopup';
import { handleOutsideClick } from '../util/handleOutsideClick';
import type { UnreadStats } from '../state/selectors/conversations';
import { NavTab } from '../state/ducks/nav';

type NavTabProps = Readonly<{
  badge?: ReactNode;
  iconClassName: string;
  id: NavTab;
  label: string;
}>;

function NavTabsItem({ badge, iconClassName, id, label }: NavTabProps) {
  return (
    <Tab id={id} data-testid={`NavTabsItem--${id}`} className="NavTabs__Item">
      <span className="NavTabs__ItemLabel">{label}</span>
      <span className="NavTabs__ItemButton">
        <span className="NavTabs__ItemContent">
          <span
            role="presentation"
            className={`NavTabs__ItemIcon ${iconClassName}`}
          />
          {badge && <span className="NavTabs__ItemBadge">{badge}</span>}
        </span>
      </span>
    </Tab>
  );
}

export type NavTabPanelProps = Readonly<{
  collapsed: boolean;
  onToggleCollapse(collapsed: boolean): void;
}>;

export type NavTabsToggleProps = Readonly<{
  i18n: LocalizerType;
  navTabsCollapsed: boolean;
  onToggleNavTabsCollapse(navTabsCollapsed: boolean): void;
}>;

export function NavTabsToggle({
  i18n,
  navTabsCollapsed,
  onToggleNavTabsCollapse,
}: NavTabsToggleProps): JSX.Element {
  function handleToggle() {
    onToggleNavTabsCollapse(!navTabsCollapsed);
  }
  return (
    <button
      type="button"
      className="NavTabs__Item NavTabs__Toggle"
      onClick={handleToggle}
    >
      <span className="NavTabs__ItemButton">
        <span
          role="presentation"
          className="NavTabs__ItemIcon NavTabs__ItemIcon--Menu"
        />
        <span className="NavTabs__ItemLabel">
          {navTabsCollapsed
            ? i18n('icu:NavTabsToggle__showTabs')
            : i18n('icu:NavTabsToggle__hideTabs')}
        </span>
      </span>
    </button>
  );
}

export type NavTabsProps = Readonly<{
  badge: BadgeType | undefined;
  hasFailedStorySends: boolean;
  hasPendingUpdate: boolean;
  i18n: LocalizerType;
  me: ConversationType;
  navTabsCollapsed: boolean;
  onShowSettings: () => void;
  onStartUpdate: () => unknown;
  onNavTabSelected(tab: NavTab): void;
  onToggleNavTabsCollapse(collapsed: boolean): void;
  onToggleProfileEditor: () => void;
  renderCallsTab(props: NavTabPanelProps): JSX.Element;
  renderChatsTab(props: NavTabPanelProps): JSX.Element;
  renderStoriesTab(props: NavTabPanelProps): JSX.Element;
  selectedNavTab: NavTab;
  storiesEnabled: boolean;
  theme: ThemeType;
  unreadConversationsStats: UnreadStats;
  unreadStoriesCount: number;
}>;

export function NavTabs({
  badge,
  hasFailedStorySends,
  hasPendingUpdate,
  i18n,
  me,
  navTabsCollapsed,
  onShowSettings,
  onStartUpdate,
  onNavTabSelected,
  onToggleNavTabsCollapse,
  onToggleProfileEditor,
  renderCallsTab,
  renderChatsTab,
  renderStoriesTab,
  selectedNavTab,
  storiesEnabled,
  theme,
  unreadConversationsStats,
  unreadStoriesCount,
}: NavTabsProps): JSX.Element {
  function handleSelectionChange(key: Key) {
    onNavTabSelected(key as NavTab);
  }

  const [targetElement, setTargetElement] = useState<HTMLElement | null>(null);
  const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null);

  const [showAvatarPopup, setShowAvatarPopup] = useState(false);

  const popper = usePopper(targetElement, popperElement, {
    placement: 'bottom-start',
    strategy: 'fixed',
    modifiers: [
      {
        name: 'offset',
        options: {
          offset: [null, 4],
        },
      },
    ],
  });

  useEffect(() => {
    const div = document.createElement('div');
    document.body.appendChild(div);
    setPortalElement(div);
    return () => {
      div.remove();
      setPortalElement(null);
    };
  }, []);

  useEffect(() => {
    return handleOutsideClick(
      () => {
        if (!showAvatarPopup) {
          return false;
        }
        setShowAvatarPopup(false);
        return true;
      },
      {
        containerElements: [portalElement, targetElement],
        name: 'MainHeader.showAvatarPopup',
      }
    );
  }, [portalElement, targetElement, showAvatarPopup]);

  useEffect(() => {
    function handleGlobalKeyDown(event: KeyboardEvent) {
      if (showAvatarPopup && event.key === 'Escape') {
        setShowAvatarPopup(false);
      }
    }
    document.addEventListener('keydown', handleGlobalKeyDown, true);
    return () => {
      document.removeEventListener('keydown', handleGlobalKeyDown, true);
    };
  }, [showAvatarPopup]);

  return (
    <Tabs orientation="vertical" className="NavTabs__Container">
      <nav
        className={classNames('NavTabs', {
          'NavTabs--collapsed': navTabsCollapsed,
        })}
      >
        <NavTabsToggle
          i18n={i18n}
          navTabsCollapsed={navTabsCollapsed}
          onToggleNavTabsCollapse={onToggleNavTabsCollapse}
        />
        <TabList
          className="NavTabs__TabList"
          selectedKey={selectedNavTab}
          onSelectionChange={handleSelectionChange}
        >
          <NavTabsItem
            id={NavTab.Chats}
            label="Chats"
            iconClassName="NavTabs__ItemIcon--Chats"
            badge={
              // eslint-disable-next-line no-nested-ternary
              unreadConversationsStats.unreadCount > 0 ? (
                <>
                  <span className="NavTabs__ItemIconLabel">
                    {i18n('icu:NavTabs__ItemIconLabel--UnreadCount', {
                      count: unreadConversationsStats.unreadCount,
                    })}
                  </span>
                  <span aria-hidden>
                    {unreadConversationsStats.unreadCount}
                  </span>
                </>
              ) : unreadConversationsStats.markedUnread ? (
                <span className="NavTabs__ItemIconLabel">
                  {i18n('icu:NavTabs__ItemIconLabel--MarkedUnread')}
                </span>
              ) : null
            }
          />
          <NavTabsItem
            id={NavTab.Calls}
            label="Calls"
            iconClassName="NavTabs__ItemIcon--Calls"
          />
          {storiesEnabled && (
            <NavTabsItem
              id={NavTab.Stories}
              label="Stories"
              iconClassName="NavTabs__ItemIcon--Stories"
              badge={
                // eslint-disable-next-line no-nested-ternary
                hasFailedStorySends
                  ? '!'
                  : unreadStoriesCount > 0
                  ? unreadStoriesCount
                  : null
              }
            />
          )}
        </TabList>
        <div className="NavTabs__Misc">
          <button
            type="button"
            className="NavTabs__Item"
            onClick={onShowSettings}
          >
            <span className="NavTabs__ItemButton">
              <span
                role="presentation"
                className="NavTabs__ItemIcon NavTabs__ItemIcon--Settings"
              />
              <span className="NavTabs__ItemLabel">
                {i18n('icu:NavTabs__ItemLabel--Settings')}
              </span>
            </span>
          </button>

          <button
            type="button"
            className="NavTabs__Item"
            data-supertab
            onClick={() => {
              setShowAvatarPopup(true);
            }}
            aria-label={i18n('icu:NavTabs__ItemLabel--Profile')}
          >
            <span className="NavTabs__ItemButton" ref={setTargetElement}>
              <span className="NavTabs__ItemContent">
                <Avatar
                  acceptedMessageRequest
                  avatarPath={me.avatarPath}
                  badge={badge}
                  className="module-main-header__avatar"
                  color={me.color}
                  conversationType="direct"
                  i18n={i18n}
                  isMe
                  phoneNumber={me.phoneNumber}
                  profileName={me.profileName}
                  theme={theme}
                  title={me.title}
                  // `sharedGroupNames` makes no sense for yourself, but
                  // `<Avatar>` needs it to determine blurring.
                  sharedGroupNames={[]}
                  size={AvatarSize.TWENTY_EIGHT}
                />
                {hasPendingUpdate && <div className="NavTabs__AvatarBadge" />}
              </span>
            </span>
          </button>
          {showAvatarPopup &&
            portalElement != null &&
            createPortal(
              <div
                id="MainHeader__AvatarPopup"
                ref={setPopperElement}
                style={{ ...popper.styles.popper, zIndex: 10 }}
                {...popper.attributes.popper}
              >
                <AvatarPopup
                  acceptedMessageRequest
                  badge={badge}
                  i18n={i18n}
                  isMe
                  color={me.color}
                  conversationType="direct"
                  name={me.name}
                  phoneNumber={me.phoneNumber}
                  profileName={me.profileName}
                  theme={theme}
                  title={me.title}
                  avatarPath={me.avatarPath}
                  hasPendingUpdate={hasPendingUpdate}
                  // See the comment above about `sharedGroupNames`.
                  sharedGroupNames={[]}
                  onEditProfile={() => {
                    onToggleProfileEditor();
                    setShowAvatarPopup(false);
                  }}
                  onStartUpdate={() => {
                    onStartUpdate();
                    setShowAvatarPopup(false);
                  }}
                  style={{}}
                />
              </div>,
              portalElement
            )}
        </div>
      </nav>
      <TabPanels>
        <TabPanel id={NavTab.Chats} className="NavTabs__TabPanel">
          {renderChatsTab}
        </TabPanel>
        <TabPanel id={NavTab.Calls} className="NavTabs__TabPanel">
          {renderCallsTab}
        </TabPanel>
        <TabPanel id={NavTab.Stories} className="NavTabs__TabPanel">
          {renderStoriesTab}
        </TabPanel>
      </TabPanels>
    </Tabs>
  );
}
