/*
 *  Copyright 2022 Collate.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import { Space, Typography } from 'antd';
import { AxiosError } from 'axios';
import { useGlobalSearchProvider } from 'components/GlobalSearchProvider/GlobalSearchProvider';
import { useTourProvider } from 'components/TourProvider/TourProvider';
import { tabsInfo } from 'constants/explore.constants';
import {
  urlGitbookDocs,
  urlGithubRepo,
  urlJoinSlack,
} from 'constants/URL.constants';
import { CurrentTourPageType } from 'enums/tour.enum';
import { isEmpty, isString, max } from 'lodash';
import { observer } from 'mobx-react';
import Qs from 'qs';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link, useHistory, useLocation } from 'react-router-dom';
import { toast } from 'react-toastify';
import { getVersion } from 'rest/miscAPI';
import { extractDetailsFromToken } from 'utils/AuthProvider.util';
import { getEntityName } from 'utils/EntityUtils';
import appState from '../../AppState';
import { ReactComponent as IconAPI } from '../../assets/svg/api.svg';
import { ReactComponent as IconDoc } from '../../assets/svg/doc.svg';
import { ReactComponent as IconExternalLink } from '../../assets/svg/external-links.svg';
import { ReactComponent as IconSlackGrey } from '../../assets/svg/slack-grey.svg';
import { ReactComponent as IconVersionBlack } from '../../assets/svg/version-black.svg';
import {
  getExplorePath,
  getTeamAndUserDetailsPath,
  getUserPath,
  ROUTES,
  TERM_ADMIN,
  TERM_USER,
  TOUR_SEARCH_TERM,
} from '../../constants/constants';
import {
  addToRecentSearched,
  getNonDeletedTeams,
} from '../../utils/CommonUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import { useAuthContext } from '../authentication/auth-provider/AuthProvider';
import NavBar from '../nav-bar/NavBar';
import './app-bar.style.less';

const Appbar: React.FC = (): JSX.Element => {
  const location = useLocation();
  const history = useHistory();
  const { t } = useTranslation();
  const { isTourOpen, updateTourPage, updateTourSearch, tourSearchValue } =
    useTourProvider();

  const {
    isAuthDisabled,
    isAuthenticated,
    isProtectedRoute,
    isTourRoute,
    onLogoutHandler,
  } = useAuthContext();

  const { searchCriteria } = useGlobalSearchProvider();

  const parsedQueryString = Qs.parse(
    location.search.startsWith('?')
      ? location.search.substr(1)
      : location.search
  );

  const searchQuery = isString(parsedQueryString.search)
    ? parsedQueryString.search
    : '';

  const [searchValue, setSearchValue] = useState(searchQuery);

  const [isOpen, setIsOpen] = useState<boolean>(false);
  const [isFeatureModalOpen, setIsFeatureModalOpen] = useState<boolean>(false);
  const [version, setVersion] = useState<string>('');

  const handleFeatureModal = (value: boolean) => {
    setIsFeatureModalOpen(value);
  };

  const handleSearchChange = (value: string) => {
    setSearchValue(value);
    if (isTourOpen) {
      updateTourSearch(value);
    } else {
      value ? setIsOpen(true) : setIsOpen(false);
    }
  };

  const supportLink = [
    {
      label: (
        <Space
          className="cursor-pointer w-full"
          size={4}
          onClick={() => history.push(ROUTES.TOUR)}>
          <SVGIcons
            alt="tour-con"
            className="align-middle m-r-xss"
            icon={Icons.TOUR}
            width="12"
          />
          <span className="text-base-color">{t('label.tour')}</span>
        </Space>
      ),
      key: 'tour',
    },
    {
      label: (
        <a
          className="link-title"
          href={urlGitbookDocs}
          rel="noreferrer"
          target="_blank">
          <Space size={4}>
            <IconDoc
              className="tw-align-middle tw--mt-0.5 tw-mr-0.5"
              height={14}
              name="Doc icon"
              width={14}
            />
            <span className="text-base-color">{t('label.doc-plural')}</span>

            <IconExternalLink
              className="text-base-color m-l-xss"
              height={14}
              width={14}
            />
          </Space>
        </a>
      ),
      key: 'docs',
    },
    {
      label: (
        <Link className="link-title" to={ROUTES.SWAGGER}>
          <Space size={4}>
            <IconAPI
              className="tw-align-middle tw--mt-0.5 tw-mr-0.5"
              height={14}
              name="API icon"
              width={14}
            />
            <span className="text-base-color">{t('label.api-uppercase')}</span>
          </Space>
        </Link>
      ),
      key: 'api',
    },
    {
      label: (
        <a
          className="link-title"
          href={urlJoinSlack}
          rel="noreferrer"
          target="_blank">
          <Space size={4}>
            <IconSlackGrey
              className="tw-align-middle tw--mt-0.5 tw-mr-0.5"
              height={14}
              name="slack icon"
              width={14}
            />
            <span className="text-base-color">{t('label.slack-support')}</span>
            <IconExternalLink
              className="text-base-color m-l-xss"
              height={14}
              width={14}
            />
          </Space>
        </a>
      ),
      key: 'slack',
    },

    {
      label: (
        <Space
          className="cursor-pointer w-full"
          size={4}
          onClick={() => handleFeatureModal(true)}>
          <SVGIcons
            alt="Doc icon"
            className="align-middle m-r-xss"
            icon={Icons.WHATS_NEW}
            width="14"
          />
          <span className="text-base-color">{t('label.whats-new')}</span>
        </Space>
      ),
      key: 'whats-new',
    },
    {
      label: (
        <a
          className="link-title"
          href={urlGithubRepo}
          rel="noreferrer"
          target="_blank">
          <Space size={4}>
            <IconVersionBlack
              className="tw-align-middle tw--mt-0.5 tw-mr-0.5"
              height={14}
              name="Version icon"
              width={14}
            />

            <span className="text-base-color hover:text-primary">{`${t(
              'label.version'
            )} ${(version ? version : '?').split('-')[0]}`}</span>

            <IconExternalLink
              className="text-base-color m-l-xss"
              height={14}
              width={14}
            />
          </Space>
        </a>
      ),
      key: 'versions',
    },
  ];

  const getUsersRoles = (userRoleArr: string[], name: string) => {
    return (
      <div>
        <div className="text-grey-muted tw-text-xs">{name}</div>
        {userRoleArr.map((userRole, i) => (
          <Typography.Paragraph
            className="ant-typography-ellipsis-custom font-normal"
            ellipsis={{ tooltip: true }}
            key={i}>
            {userRole}
          </Typography.Paragraph>
        ))}
        <hr className="tw-my-1.5" />
      </div>
    );
  };

  const getUserName = () => {
    const currentUser = isAuthDisabled
      ? appState.nonSecureUserDetails
      : appState.userDetails;

    return currentUser?.displayName || currentUser?.name || TERM_USER;
  };

  const getUserData = () => {
    const currentUser = isAuthDisabled
      ? appState.nonSecureUserDetails
      : appState.userDetails;

    const name = currentUser?.displayName || currentUser?.name || TERM_USER;

    const roles = currentUser?.roles?.map((r) => getEntityName(r)) || [];
    const inheritedRoles =
      currentUser?.inheritedRoles?.map((r) => getEntityName(r)) || [];

    currentUser?.isAdmin && roles.unshift(TERM_ADMIN);

    const userTeams = getNonDeletedTeams(currentUser?.teams ?? []);

    const teams = userTeams.splice(0, 3);
    const remainingTeamsCount = max([userTeams.length, 0]);

    return (
      <div className="tw-max-w-xs" data-testid="greeting-text">
        <Link
          data-testid="user-name"
          to={getUserPath(currentUser?.name as string)}>
          {' '}
          <Typography.Paragraph
            className="ant-typography-ellipsis-custom font-medium cursor-pointer text-link-color"
            ellipsis={{ rows: 1, tooltip: true }}>
            {name}
          </Typography.Paragraph>
        </Link>
        <hr className="tw-my-1.5" />
        {roles.length > 0 ? getUsersRoles(roles, t('label.role-plural')) : null}
        {inheritedRoles.length > 0
          ? getUsersRoles(inheritedRoles, t('label.inherited-role-plural'))
          : null}
        {teams.length > 0 ? (
          <div>
            <span className="text-grey-muted tw-text-xs">
              {t('label.team-plural')}
            </span>
            {teams.map((t, i) => (
              <Typography.Paragraph
                className="ant-typography-ellipsis-custom text-sm"
                ellipsis={{ tooltip: true }}
                key={i}>
                <Link to={getTeamAndUserDetailsPath(t.name as string)}>
                  {t.displayName || t.name}
                </Link>
              </Typography.Paragraph>
            ))}
            {remainingTeamsCount ? (
              <Link
                className="more-teams-pill"
                to={getUserPath(currentUser?.name as string)}>
                {remainingTeamsCount} {t('label.more')}
              </Link>
            ) : null}
          </div>
        ) : null}
      </div>
    );
  };

  const profileDropdown = [
    {
      name: getUserData(),
      to: '',
      disabled: false,
      icon: <></>,
      isText: true,
    },
  ];

  const searchHandler = (value: string) => {
    if (!isTourOpen) {
      setIsOpen(false);
      addToRecentSearched(value);

      const defaultTab: string =
        searchCriteria !== '' ? tabsInfo[searchCriteria].path : '';

      history.push(
        getExplorePath({
          tab: defaultTab,
          search: value,
          isPersistFilters: false,
        })
      );
    }
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    const target = e.target as HTMLInputElement;
    if (e.key === 'Enter') {
      if (isTourOpen && searchValue === TOUR_SEARCH_TERM) {
        updateTourPage(CurrentTourPageType.EXPLORE_PAGE);
        updateTourSearch('');
      }

      searchHandler(target.value);
    }
  };

  const handleOnclick = () => {
    searchHandler(searchValue);
  };

  const handleClear = () => {
    setSearchValue('');
    searchHandler('');
  };

  const fetchOMVersion = () => {
    getVersion()
      .then((res) => {
        setVersion(res.version);
      })
      .catch((err: AxiosError) => {
        showErrorToast(
          err,
          t('server.entity-fetch-error', {
            entity: t('label.version'),
          })
        );
      });
  };

  useEffect(() => {
    setSearchValue(searchQuery);
  }, [searchQuery]);
  useEffect(() => {
    if (isTourOpen) {
      setSearchValue(tourSearchValue);
    }
  }, [tourSearchValue, isTourOpen]);

  useEffect(() => {
    if (isAuthDisabled) {
      fetchOMVersion();
    } else {
      if (!isEmpty(appState.userDetails)) {
        fetchOMVersion();
      }
    }
  }, [appState.userDetails, isAuthDisabled]);

  useEffect(() => {
    const handleDocumentVisibilityChange = () => {
      if (
        isProtectedRoute(location.pathname) &&
        isTourRoute(location.pathname)
      ) {
        return;
      }
      const { isExpired, exp } = extractDetailsFromToken();
      if (!document.hidden && isExpired) {
        exp && toast.info(t('message.session-expired'));
        onLogoutHandler();
      }
    };

    addEventListener('focus', handleDocumentVisibilityChange);

    return () => {
      removeEventListener('focus', handleDocumentVisibilityChange);
    };
  }, []);

  return (
    <>
      {isProtectedRoute(location.pathname) &&
      (isAuthDisabled || isAuthenticated) ? (
        <NavBar
          handleClear={handleClear}
          handleFeatureModal={handleFeatureModal}
          handleKeyDown={handleKeyDown}
          handleOnClick={handleOnclick}
          handleSearchBoxOpen={setIsOpen}
          handleSearchChange={handleSearchChange}
          isFeatureModalOpen={isFeatureModalOpen}
          isSearchBoxOpen={isOpen}
          pathname={location.pathname}
          profileDropdown={profileDropdown}
          searchValue={searchValue || ''}
          supportDropdown={supportLink}
          username={getUserName()}
        />
      ) : null}
    </>
  );
};

export default observer(Appbar);
