/* eslint-disable react/prop-types */
import React, { useState } from 'react';
import isNull from 'lodash/isNull';
import PropTypes from 'prop-types';

import Badge, { Variant } from '@leafygreen-ui/badge';
import { cx } from '@leafygreen-ui/emotion';
import { useViewportSize } from '@leafygreen-ui/hooks';
// @ts-expect-error
import CaretDownIcon from '@leafygreen-ui/icon/dist/CaretDown';
import { useDarkMode } from '@leafygreen-ui/leafygreen-provider';
import { AtlasNavGraphic, MongoDBLogoMark } from '@leafygreen-ui/logo';
import Tooltip from '@leafygreen-ui/tooltip';

import { breakpoints } from '../breakpoints';
import { OrgSelect } from '../mongo-select';
import { useMongoNavContext } from '../MongoNavContext';
import { useOnElementClick } from '../on-element-click-provider';
import {
  navContainerBaseStyle,
  navContainerThemeStyle,
  navSectionStyle,
} from '../styles';
import {
  AccountInterface,
  ActiveNavElement,
  Environment,
  MongoNavInterface,
  NavElement,
  OrganizationInterface,
  OrgPaymentLabel,
  URLS,
} from '../types';

import {
  FullWidthGovBanner,
  GetHelpDropdownMenu,
  MobileGovTooltip,
  OrgNavLink,
  VersionNumber,
  VersionNumberStyle,
} from './org-nav-helpers';
import {
  logoLinkFocusThemeStyle,
  logoLinkStyles,
  logoMarkClassName,
  orgNavContainerBaseStyle,
  orgNavContainerThemeStyle,
  orgNavLinkWrapperClassName,
} from './OrgNav.styles';
import UserMenu, { OnPremUserMenu } from './UserMenu';
import { AccessManagerControl } from './org-nav-helpers/AccessManagerControl';

const paymentStatusMap: {
  [K in Partial<Variant>]?: ReadonlyArray<OrgPaymentLabel>;
} = {
  [Variant.LightGray]: [
    OrgPaymentLabel.Embargoed,
    OrgPaymentLabel.EmbargoConfirmed,
  ],
  [Variant.Green]: [OrgPaymentLabel.Ok],
  [Variant.Yellow]: [
    OrgPaymentLabel.Warning,
    OrgPaymentLabel.Suspended,
    OrgPaymentLabel.Closing,
  ],
  [Variant.Red]: [
    OrgPaymentLabel.Dead,
    OrgPaymentLabel.AdminSuspended,
    OrgPaymentLabel.Locked,
    OrgPaymentLabel.Closed,
  ],
} as const;

const userMenuActiveNavItems = [
  ActiveNavElement.UserMenuCloudInvitations,
  ActiveNavElement.UserMenuCloudMFA,
  ActiveNavElement.UserMenuCloudOrganizations,
  ActiveNavElement.UserMenuCloudUserPreferences,
  ActiveNavElement.UserMenuCloudOther,
  ActiveNavElement.UserMenuOnPremInvitations,
  ActiveNavElement.UserMenuOnPremOrganizations,
  ActiveNavElement.UserMenuOnPremPersonalization,
  ActiveNavElement.UserMenuOnPremProfile,
  ActiveNavElement.UserMenuOnPremPublicApiAccess,
  ActiveNavElement.UserMenuOnPremTwoFactorAuth,
  ActiveNavElement.UserMenuOnPremOther,
  ActiveNavElement.OrgNavAllClusters,
];

function NavLinks({
  loading,
  admin,
  onPremVersion,
  urls,
  activeNav,
}: {
  loading: boolean;
  admin: boolean;
  onPremVersion?: string;
  urls: URLS['orgNav'];
  activeNav?: ActiveNavElement;
}) {
  const onElementClick = useOnElementClick();

  const navLinks: Array<{
    href?: string;
    navId: NavElement;
    text: string;
    testid: string;
  }> = [];

  navLinks.push({
    href: urls.allClusters,
    navId: ActiveNavElement.OrgNavAllClusters,
    text: 'All Clusters',
    testid: 'org-nav-all-clusters-link',
  });

  if (admin) {
    navLinks.push({
      href: urls.admin,
      navId: ActiveNavElement.OrgNavAdmin,
      text: 'Admin',
      testid: 'org-nav-admin-link',
    });
  }

  const items = navLinks.map(({ href, navId, text, testid }) => (
    <OrgNavLink
      href={href}
      loading={loading}
      isActive={activeNav === navId}
      key={navId}
      onClick={onElementClick(navId)}
      data-testid={testid}
    >
      <span className={orgNavLinkWrapperClassName}>{text}</span>
    </OrgNavLink>
  ));

  return (
    <>
      {onPremVersion && (
        <VersionNumber style={VersionNumberStyle.Nav} key={onPremVersion}>
          {onPremVersion}
        </VersionNumber>
      )}

      {items}
    </>
  );
}

export type OrgNavProps = Pick<
  MongoNavInterface,
  'onOrganizationChange' | 'admin' | 'mode' | 'activePlatform' | 'environment'
> & {
  account?: AccountInterface;
  data?: Array<OrganizationInterface>;
  currentProjectName?: string;
  currentProjectId?: string;
  onPremEnabled?: boolean;
  onPremVersion?: string;
  onPremMFA?: boolean;
  constructOrganizationURL: NonNullable<
    MongoNavInterface['constructOrganizationURL']
  >;
  urls: URLS;
  hosts: Required<NonNullable<MongoNavInterface['hosts']>>;
  showProjectNav: NonNullable<MongoNavInterface['showProjectNav']>;
};

function OrgNav({
  account,
  data,
  mode,
  constructOrganizationURL,
  onOrganizationChange,
  urls,
  admin,
  hosts,
  currentProjectName = 'None',
  activePlatform,
  currentProjectId,
  onPremEnabled,
  onPremVersion,
  onPremMFA = false,
  showProjectNav,
  environment,
}: OrgNavProps) {
  const [onPremMenuOpen, setOnPremMenuOpen] = useState(false);
  const onElementClick = useOnElementClick();
  const viewportSize = useViewportSize();
  const { theme, darkMode } = useDarkMode();
  const {
    isLoading,
    activeNav,
    currentProject,
    currentOrg: current,
  } = useMongoNavContext();

  const isGovernment = environment === Environment.Government;
  const isTablet = viewportSize
    ? viewportSize.width < breakpoints.medium
    : false;
  const isMobile = viewportSize
    ? viewportSize.width < breakpoints.small
    : false;

  const isActiveNavInUserMenu = (
    userMenuActiveNavItems as Array<string>
  ).includes(activeNav as string);

  let paymentVariant: Variant | undefined;
  let key: Variant;

  for (key in paymentStatusMap) {
    const paymentStatus = current?.paymentStatus;

    if (paymentStatus && paymentStatusMap[key]?.includes(paymentStatus)) {
      paymentVariant = key;
    }
  }

  const paymentValues: Array<OrgPaymentLabel> = [
    OrgPaymentLabel.Suspended,
    OrgPaymentLabel.Locked,
    OrgPaymentLabel.AdminSuspended,
  ];

  const shouldShowBadge = !(
    isActiveNavInUserMenu ||
    current?.paymentStatus == null ||
    isTablet ||
    onPremEnabled ||
    !paymentVariant ||
    (!admin && !paymentValues.includes(current.paymentStatus))
  );

  const paymentStatusDisplayName =
    shouldShowBadge &&
    (current?.paymentStatusDisplayName ??
      current.paymentStatus!.split('_').join(' '));

  const showAtlasGraphic =
    !onPremEnabled &&
    !isActiveNavInUserMenu &&
    currentProject?.planType === 'atlas';

  const LogoComponent = showAtlasGraphic ? AtlasNavGraphic : MongoDBLogoMark;

  const RenderedUserMenu = () => {
    return onPremEnabled ? (
      <OnPremUserMenu
        name={account?.firstName ?? ''}
        open={onPremMenuOpen}
        setOpen={setOnPremMenuOpen}
        urls={urls}
        mfa={onPremMFA}
        activeNav={activeNav}
      />
    ) : (
      <UserMenu
        account={account}
        activePlatform={activePlatform}
        urls={urls}
        hosts={hosts}
        activeNav={activeNav}
        environment={environment}
        loading={isLoading}
      />
    );
  };

  const { orgNav } = urls;

  return (
    <>
      {!isMobile && isGovernment && <FullWidthGovBanner isTablet={isTablet} />}
      <nav
        className={cx(
          navContainerBaseStyle,
          navContainerThemeStyle[theme],
          orgNavContainerBaseStyle,
          orgNavContainerThemeStyle[theme],
        )}
        aria-label="organization navigation"
        data-testid="organization-nav"
      >
        <div className={cx(navSectionStyle)}>
          <Tooltip
            aria-hidden
            align="bottom"
            justify="start"
            onClick={e => e.preventDefault()}
            usePortal={false}
            trigger={
              <a
                href={orgNav.leaf}
                onClick={onElementClick(NavElement.OrgNavLeaf)}
                data-testid="org-nav-leaf"
                className={cx(logoLinkStyles, logoLinkFocusThemeStyle[theme])}
              >
                <LogoComponent
                  className={logoMarkClassName}
                  height={32}
                  aria-label="Go to the Organization Home"
                  color={darkMode ? 'green-base' : 'green-dark-2'}
                />
              </a>
            }
          >
            View the Organization Home
          </Tooltip>

          {isMobile && isGovernment && <MobileGovTooltip />}

          <OrgSelect
            data={data}
            current={current}
            mode={mode}
            constructOrganizationURL={constructOrganizationURL}
            hosts={hosts}
            urls={urls.mongoSelect}
            onChange={onOrganizationChange}
            isActive={activeNav === ActiveNavElement.OrgNavOrgSettings}
            disabled={isActiveNavInUserMenu}
            admin={admin}
            isOnPrem={onPremEnabled}
          />

          {shouldShowBadge && (
            <Badge
              variant={paymentVariant}
              data-testid="org-nav-payment-status"
            >
              {paymentStatusDisplayName}
            </Badge>
          )}

          {!isActiveNavInUserMenu && !isMobile && (
            <>
              <AccessManagerControl
                onPremEnabled={onPremEnabled}
                urls={urls}
                showProjectNav={showProjectNav}
              />

              {!onPremEnabled && (
                <OrgNavLink
                  href={current ? orgNav.billing : undefined}
                  isActive={activeNav === ActiveNavElement.OrgNavBilling}
                  loading={isLoading}
                  data-testid="org-nav-billing"
                  onClick={onElementClick(NavElement.OrgNavBilling)}
                  disabled={isNull(current)}
                >
                  <span className={orgNavLinkWrapperClassName}>Billing</span>
                </OrgNavLink>
              )}
            </>
          )}
        </div>

        <div className={navSectionStyle}>
          {!isMobile && (
            <NavLinks
              loading={isLoading}
              admin={!!admin}
              onPremVersion={onPremEnabled ? onPremVersion : undefined}
              urls={urls.orgNav}
              activeNav={activeNav}
            />
          )}

          <div className={navSectionStyle}>
            <GetHelpDropdownMenu
              loading={isLoading}
              activeNav={activeNav}
              isTablet={isTablet}
              isMobile={isMobile}
              urls={urls}
            />
            <RenderedUserMenu />
          </div>
        </div>
      </nav>
    </>
  );
}

OrgNav.displayName = 'OrgNav';

OrgNav.propTypes = {
  current: PropTypes.shape({
    paymentStatus: PropTypes.string,
  }),
};

export default OrgNav;
