import { useCallback, useRef } from 'react';

import type { CSSProperties, FC, ReactNode, RefObject } from 'react';
import type { BaseLayoutProps } from '../types';

import Box from '~/src/components/Box';
import Gradient from '~/src/components/Gradient';
import Page from '~/src/components/Page';
import Sticky from '~/src/components/Sticky';
import { toRgba } from '~/src/lib/utils/color';
import { usePageTheme } from '../../hooks/theme';
import useOnScrollCallback from './useOnScrollCallback';

const MAX_CONTENT_WIDTH = '48rem';

export interface SingleColumnLayoutProps extends BaseLayoutProps {
  spaceAboveContent: string;
  beforeContent?: ReactNode;
  imageGradients?: boolean;
  spaceBetweenSections: string;
  contentStyle?: CSSProperties;
  children?: ReactNode;
  renderBackground: (param: {
    imageRef: RefObject<HTMLDivElement | null>;
  }) => ReactNode;
}

const SingleColumnLayout: FC<SingleColumnLayoutProps> = ({
  beforeContent,
  content,
  header,
  footer,
  children,
  spaceAboveContent,
  imageGradients,
  renderBackground,
  spaceBetweenSections,
  contentRootRef,
  onScroll,
  contentStyle,
  ...pageProps
}) => {
  const headerContentRef = useRef<HTMLDivElement>(null);
  const imageRef = useRef<HTMLDivElement>(null);
  const pageTheme = usePageTheme();

  const onScrollInternal = useOnScrollCallback({
    headerContentRef,
    imageRef,
  });

  return (
    <Page
      backgroundColor={pageTheme.backgroundColor}
      textColor={pageTheme.textColor}
      contentStyle={{
        paddingBottom: 0,
      }}
      onScroll={useCallback((params) => {
        onScrollInternal(params);
        onScroll?.();
      }, [])}
      renderBackground={useCallback(() => {
        return renderBackground({ imageRef });
      }, [renderBackground])}
      renderHeader={useCallback(() => {
        return header.content;
      }, [header])}
      renderContent={useCallback(
        ({ contentContainerProps }) => {
          return (
            <Box flexColumn minHeight="100%" {...contentContainerProps}>
              <Box
                nodeRef={contentRootRef}
                flexGrow
                flexColumn
                style={{
                  background: `linear-gradient(180deg, transparent 0%, transparent 100vh, ${pageTheme.gradientColor} 100%)`,
                }}
              >
                <Sticky
                  zIndex={1}
                  style={{
                    marginTop: '-8rem',
                    marginBottom: '-2rem',
                    pointerEvents: 'none',
                  }}
                >
                  <Gradient
                    from={toRgba(
                      pageTheme.backgroundColor,
                      (0.65 * pageTheme.gradientOpacity) / 100
                    )}
                    to={toRgba(pageTheme.backgroundColor, 0)}
                    height="10rem"
                  />
                </Sticky>
                <Box
                  style={{
                    // grow to fill available space so that when section content is shorter than
                    // viewport we don't see where the gradient (defined below) ends
                    flexGrow: 1,
                    flexShrink: 0,
                    position: 'relative',
                  }}
                >
                  <div
                    style={{
                      margin: '0 auto',
                      padding: `0 1.4rem 10rem`,
                      maxWidth: MAX_CONTENT_WIDTH,
                      // content-box for padding outside
                      boxSizing: 'content-box',
                      ...contentStyle,
                    }}
                  >
                    <Box
                      centerContent
                      margin={`0 0 2rem`}
                      minHeight={spaceAboveContent}
                    >
                      {beforeContent}
                    </Box>
                    {content}
                  </div>
                </Box>
                {children}
              </Box>
              <style jsx>
                {`
                  :global(.pageSection:not(:first-of-type)) {
                    margin-top: ${spaceBetweenSections};
                  }

                  :global(.pageSection.isGrouped:not(:first-child)) {
                    margin-top: 2rem;
                  }
                `}
              </style>
            </Box>
          );
        },
        [
          content,
          beforeContent,
          spaceAboveContent,
          header.height,
          spaceBetweenSections,
          pageTheme,
        ]
      )}
      renderFooter={useCallback(() => {
        return footer?.content;
      }, [footer])}
      footerHeight={footer?.height}
      footerStyle={{ pointerEvents: 'none' }}
      // trackPageView={!!hasContent}
      withOverflowGradients
      gradientColor={pageTheme.backgroundColor}
      gradientAlpha={(0.7 * pageTheme.gradientOpacity) / 100}
      {...pageProps}
    />
  );
};

export default SingleColumnLayout;
