import { useCallback, useMemo, useState } from 'react';
import dynamic from 'next/dynamic';

import type { ClickableOnClick } from '~/src/components/Clickable';
import type { PageSectionComponent } from '../types';
import type { ItemLinksProps } from './types';

import Box from '~/src/components/Box';
import Clickable from '~/src/components/Clickable';
import Text from '~/src/components/Text';
import { useI18n } from '~/src/lib/i18n';
import { useSelector } from '~/src/store/redux';
import { selectUserCountry } from '~/src/store/session/selectors';
import { useRegisterNavItem } from '../../components/ItemPageNav/useItemPageNav';
import { usePageTheme } from '../../hooks/theme';
import { resolveLinks } from '../lib';
import SectionTitle from '../lib/SectionTitle';
import ServiceButton, { DEFAULT_HEIGHT_REM } from '../lib/ServiceButton';
import useOpenLink from '../lib/useOpenLink';

const PagePeekDynamic = dynamic(() => import('../lib/PagePeek'), {
  ssr: false,
});

const MARGIN_BOTTOM_REM = DEFAULT_HEIGHT_REM * 0.175;
const DEFAULT_ITEMS_VISIBLE = 7;
const Y_PADDING_REM = 0.5;

const CLAMPED_HEIGHT_REM =
  DEFAULT_ITEMS_VISIBLE * (DEFAULT_HEIGHT_REM + MARGIN_BOTTOM_REM) -
  MARGIN_BOTTOM_REM;

// TODO: rename this ButtonLinksSection
const ItemLinks: PageSectionComponent<ItemLinksProps> = ({
  title: defaultTitle,
  links: defaultLinks,
  layoutData,
  withShowMore,
  withColoredIcons,

  // orchard/owned pages default to alphabetical sort
  withAlphabeticalSort = layoutData.item.isOwned,

  territoryOverrides,
  sectionId,
  sectionIndex,
  navTitle,
}) => {
  const { t } = useI18n();
  const userCountry = useSelector(selectUserCountry);
  const links = territoryOverrides?.[userCountry]?.links || defaultLinks;
  const title = territoryOverrides?.[userCountry]?.title || defaultTitle;
  const [isExpanded, setIsExpanded] = useState(!withShowMore);
  const [pagePeekPath, setPagePeekPath] = useState<string>();
  const pageTheme = usePageTheme();
  const openLink = useOpenLink();

  const onShowMoreClick = useCallback(() => {
    setIsExpanded(true);
  }, []);

  useRegisterNavItem({
    id: sectionId,
    text: navTitle,
    index: sectionIndex,
  });

  const linksResolved = useMemo(
    () => resolveLinks({ layoutData, links }),
    [links]
  );

  const onClickInternal = useCallback<
    ClickableOnClick<{ pagePeeking: boolean | undefined; link: string }>
  >(({ event, data: { pagePeeking, link } }) => {
    event.preventDefault();

    const buttonText = event.currentTarget.textContent ?? 'empty';

    openLink({
      url: link,
      name: buttonText,
      pagePeeking,
      onPagePeek: setPagePeekPath,
    });
  }, []);

  // unable to resolve any links from given props
  if (!linksResolved) return null;

  const filteredLinks = linksResolved.filter(({ service }) =>
    linkButtonShouldRender({ countries: service.countries, userCountry })
  );

  const linksToRender = withAlphabeticalSort
    ? [...filteredLinks].sort((a, b) => a.text.localeCompare(b.text))
    : filteredLinks;

  const hasOverflowingItems = linksToRender.length > DEFAULT_ITEMS_VISIBLE;
  const showMoreButtonVisible = !isExpanded && hasOverflowingItems;

  const maxHeight = !isExpanded
    ? `${CLAMPED_HEIGHT_REM + Y_PADDING_REM * 2}rem`
    : undefined;

  return (
    <Box testId="itemLinks">
      <SectionTitle margin="0 0 2rem" text={title} />
      <Box
        maxHeight={maxHeight}
        margin={`-${Y_PADDING_REM}rem 0`}
        padding={`${Y_PADDING_REM}rem 1.2rem`}
        style={{
          overflow: 'hidden',
        }}
      >
        {linksToRender.map(
          ({ text, link, Icon, serviceType, pagePeeking }, index) => {
            const isLast = index === links.length - 1;
            const margin = !isLast ? `0 0 ${MARGIN_BOTTOM_REM}rem` : undefined;
            const isHidden = !isExpanded && index + 1 > DEFAULT_ITEMS_VISIBLE;

            // when the button is hidden in the overflow then
            // we don't want users to be able to tab to it
            const tabIndex = isHidden ? -1 : 0;

            return (
              <ServiceButton
                key={link}
                serviceType={serviceType}
                href={link}
                text={text}
                Icon={Icon}
                tabIndex={tabIndex}
                margin={margin}
                withColoredIcon={withColoredIcons}
                onClick={onClickInternal}
                data={{
                  pagePeeking,
                  link,
                }}
              />
            );
          }
        )}
      </Box>
      {showMoreButtonVisible && (
        <Clickable
          tabIndex={0}
          onClick={onShowMoreClick}
          margin="2.2rem 0 0 0"
          testId="showMore"
        >
          <Text
            size="1.7rem"
            isBold
            centered
            family={pageTheme.fontFamily}
            color={pageTheme.customFontColor}
          >
            {t('app.actions.showMore')}
          </Text>
        </Clickable>
      )}
      {pagePeekPath && (
        <PagePeekDynamic
          pagePath={pagePeekPath}
          onClose={() => {
            setPagePeekPath(undefined);
          }}
        />
      )}
    </Box>
  );
};

const linkButtonShouldRender = ({
  userCountry,
  countries,
}: {
  userCountry: string;
  countries: string[] | undefined;
}) => {
  // when a userCountry is defined we check the service is available
  // in that country before rendering the button
  return !userCountry || !countries || !!~countries.indexOf(userCountry);
};

export default ItemLinks;
