import { useCallback, useEffect, useRef } from 'react';

import type { ModalProps } from '~/src/components/Modal';
import type { TransitionInOut2Api } from '~/src/components/TransitionInOut2';
import type { SelectedAlbum } from '~/src/store/albums/types';
import type { SelectedTrack } from '~/src/store/tracks/types';
import type { SelectedCustomPage, SelectedItem } from '~/src/store/types';
import type { FC } from 'react';
import type { ItemContext } from '../../../types';

import { ItemTypes } from '~/lib/types';
import Box from '~/src/components/Box';
import Clickable from '~/src/components/Clickable';
import ErrorText from '~/src/components/ErrorText';
import Gradient from '~/src/components/Gradient';
import Modal from '~/src/components/Modal';
import PageLoading from '~/src/components/PageLoading';
import Text from '~/src/components/Text';
import TransitionInOut2 from '~/src/components/TransitionInOut2';
import useFetchItemByPath from '~/src/hooks/useFetchItemByPath';
import { toPublicEndpoint } from '~/src/lib/getPublicEndpoint';
import { useI18n } from '~/src/lib/i18n';
import { ALBUM_PAGE_SECTION_COMPONENTS } from '~/src/views/AlbumPage/constants';
import useAlbumChecks from '~/src/views/AlbumPage/hooks/useAlbumChecks';
import useAlbumItemContext from '~/src/views/AlbumPage/hooks/useAlbumItemContext';
import useCustomPageContext from '~/src/views/CustomPage/useCustomPageContext';
import useTrackChecks from '~/src/views/TrackPage/useTrackChecks';
import useTrackItemContext from '~/src/views/TrackPage/useTrackItemContext';
import { PageSections } from '../../../components/SectionRenderer';
import { CORE_SECTION_COMPONENTS, MAX_CONTENT_WIDTH } from '../../../constants';
import { PageSectionTypes } from '../../types';

const SECTION_COMPONENTS = {
  ...CORE_SECTION_COMPONENTS,
  ...ALBUM_PAGE_SECTION_COMPONENTS,
};

const PagePeek: FC<
  { pagePath: string } & Omit<ModalProps, 'renderContent'>
> = ({ pagePath, ...modalProps }) => {
  const result = useFetchItemByPath(pagePath);
  const { t } = useI18n('item');

  return (
    <Modal
      {...modalProps}
      testId="pagePeekModal"
      withScroller
      withSlideIn
      style={{
        width: '100%',
        maxWidth: `calc(${MAX_CONTENT_WIDTH} + 2.8rem)`,
        padding: 0,
      }}
      renderAfter={useCallback(() => {
        // serving Songwhip on custom domains does not allow us to
        // navigate directly by path staying on the same domain (link with path href)
        const href = toPublicEndpoint(pagePath);
        const linkText = t('pagePeekingVisitLink');

        return (
          <Gradient
            to="rgba(0,0,0,0.9)"
            positionAbsolute
            left={0}
            bottom={0}
            right={0}
            centerContent
            padding="4rem 0 0"
            pointerEvents="none"
          >
            <Clickable
              href={href}
              isInline
              testId="viewPage"
              isCentered
              padding="2rem"
              pointerEvents="all"
            >
              <Text
                noWrap
                size="1.3rem"
                color="#999"
                isUnderline
                shadow="0 0 1rem #000"
              >
                {linkText}
              </Text>
            </Clickable>
          </Gradient>
        );
      }, [pagePath])}
      renderContent={useCallback(() => {
        return <PagePeakContentWrapper {...result} />;
      }, [result])}
    />
  );
};

const PagePeakContent: FC<{
  itemContext: ItemContext;
  itemIsLoading?: boolean;
  itemError?: Error;
}> = ({ itemContext, itemIsLoading, itemError }) => {
  const transitionApiRef = useRef<TransitionInOut2Api>(null);

  useEffect(() => {
    if (itemIsLoading) return;
    transitionApiRef.current?.setVisible(true);
  }, [itemIsLoading]);

  if (itemIsLoading) {
    return (
      <Box height="6rem" positionRelative>
        <PageLoading />
      </Box>
    );
  }

  if (itemError) {
    return <ErrorText error={itemError} centered />;
  }

  // This is not always going to be the ItemLinks section if the user
  // has a custom page layout. We may want to review this in the future
  // to always render ItemLinks (for non-prerelease pages) and get the links
  // from the config.layout, the list would show all the links on the page.
  // If the first section is ItemLinks then we could just skip this.
  // Or we could just render the first ItemLinks section?
  const firstSection = itemContext.layout.main.find(({ component }) => {
    return (
      component !== PageSectionTypes.PAGE_TITLE &&
      component !== PageSectionTypes.ICON_LINKS
    );
  });

  if (!firstSection) {
    return <Text>No content</Text>;
  }

  return (
    <TransitionInOut2
      apiRef={transitionApiRef}
      isVisibleInitial={false}
      padding="7rem 0"
    >
      <PageSections
        components={SECTION_COMPONENTS}
        itemContext={itemContext}
        items={[firstSection]}
        id=""
      />
    </TransitionInOut2>
  );
};

const PagePeakAlbumContent: FC<{
  item: SelectedAlbum;
  itemIsLoading?: boolean;
  itemError?: Error;
}> = ({ item, itemIsLoading, itemError }) => {
  useAlbumChecks(item);

  const itemContext = useAlbumItemContext({
    album: item,
  });

  return (
    <PagePeakContent
      itemContext={itemContext}
      itemIsLoading={itemIsLoading}
      itemError={itemError}
    />
  );
};

const PagePeakTrackContent: FC<{
  item: SelectedTrack;
  itemIsLoading?: boolean;
  itemError?: Error;
}> = ({ item, itemIsLoading, itemError }) => {
  useTrackChecks(item);

  const itemContext = useTrackItemContext({
    track: item,
  });

  return (
    <PagePeakContent
      itemContext={itemContext}
      itemIsLoading={itemIsLoading}
      itemError={itemError}
    />
  );
};

const PagePeakCustomPageContent: FC<{
  item: SelectedCustomPage;
  itemIsLoading?: boolean;
  itemError?: Error;
}> = ({ item, itemIsLoading, itemError }) => {
  const itemContext = useCustomPageContext({
    customPage: item,
  });

  return (
    <PagePeakContent
      itemContext={itemContext}
      itemIsLoading={itemIsLoading}
      itemError={itemError}
    />
  );
};

const PagePeakContentWrapper: FC<{
  item?: SelectedItem | SelectedCustomPage;
  itemIsLoading?: boolean;
  itemError?: Error;
}> = ({ item, itemIsLoading, itemError }) => {
  if (item?.type === ItemTypes.ALBUM) {
    return (
      <PagePeakAlbumContent
        item={item}
        itemIsLoading={itemIsLoading}
        itemError={itemError}
      />
    );
  }

  if (item?.type === ItemTypes.TRACK) {
    return (
      <PagePeakTrackContent
        item={item}
        itemIsLoading={itemIsLoading}
        itemError={itemError}
      />
    );
  }

  if (item?.type === ItemTypes.CUSTOM_PAGE) {
    return (
      <PagePeakCustomPageContent
        item={item}
        itemIsLoading={itemIsLoading}
        itemError={itemError}
      />
    );
  }

  // TODO: handle fallback better
  return null;
};

export default PagePeek;
