import React, { useEffect, useRef } from 'react';
import { createStyledComponent } from '@cloudflare/style-container';
import { Main, Header, Div, P, Span } from '@cloudflare/elements';
import { Label } from '@cloudflare/component-label';
import { Trans } from '@cloudflare/intl-react';
import { Heading, Section } from './Heading';
import { DocumentationLink, Link } from '@cloudflare/component-link';
import { useIsMobile } from '@cloudflare/util-responsive';
import { Icon } from '@cloudflare/component-icon';
import { Button } from '@cloudflare/component-button';
import { Tooltip } from '@cloudflare/component-tooltip';
import { useLocation } from '@cloudflare/util-cl1-compat-router';

type PageWidth = 'narrow' | 'wide' | 'unbounded';

type PageHeaderProps = {
  title?: React.ReactNode;
  parentPageLabel?: React.ReactNode;
  description?: React.ReactNode;
  documentationLabel?: React.ReactNode;
  documentationHref?: string;
  control?: React.ReactNode;
  children?: React.ReactNode;
  centerHeader?: boolean;
  beta?: boolean;
  titleRef?: React.RefObject<HTMLHeadingElement>;
  parentPageLabelRef?: React.RefObject<HTMLHeadingElement>;
  navigation?: React.ReactNode;
  onDocumentationButtonClick?: () => void;
  documentationAsButton?: boolean;
};

type Props = PageHeaderProps & {
  type?: PageWidth;
  className?: string;
  testId?: string;
  sidebar?: React.ReactNode;
  sidebarPosition?: 'outside' | 'inside' | 'left';
  autofocus?: boolean;
};

const maxWidthByType = {
  narrow: '64em',
  wide: '79em',
  unbounded: '100%'
};

const maxPageTitles = 2;

const PageHeader = ({
  title,
  parentPageLabel,
  description,
  documentationLabel,
  documentationHref,
  centerHeader,
  control,
  children,
  beta,
  titleRef,
  parentPageLabelRef,
  navigation,
  onDocumentationButtonClick,
  documentationAsButton
}: PageHeaderProps) => {
  const headerVisible = !!(title || description);
  const titlesCount = Math.min([title, description].filter(Boolean).length, 2);
  const isMobile = useIsMobile();

  return (
    <>
      {navigation && !isMobile && <Div mb={4}>{navigation}</Div>}
      <Div
        display={control ? ['block', 'flex'] : 'block'}
        justifyContent="space-between"
        mb={headerVisible ? 3 : 0}
      >
        <Header textAlign={centerHeader ? 'center' : undefined}>
          {parentPageLabel && (
            <P
              my={0}
              lineHeight={1.5}
              color="gray.3"
              fontWeight={600}
              innerRef={parentPageLabelRef}
            >
              {parentPageLabel}
            </P>
          )}
          {title && (
            <Div display="flex" alignItems="center">
              <Heading mt={0} mb={2} innerRef={titleRef}>
                {isMobile && navigation && React.isValidElement(navigation) && (
                  <Link mr={2} onClick={navigation.props.onClick}>
                    <Icon type="backward" />
                  </Link>
                )}
                {title}
              </Heading>
              {beta && (
                <Label hue="orange" mx={2} verticalAlign="middle">
                  <Trans _="Beta" id="common.beta" />
                </Label>
              )}
            </Div>
          )}
          {description && (
            <P
              color="gray.3"
              mt={0}
              mb={documentationHref ? 2 : 3}
              lineHeight={1.25}
              fontWeight={400}
              wordBreak="break-word"
            >
              {description}
            </P>
          )}
          {documentationAsButton && !isMobile ? (
            <Tooltip
              place="right"
              message={
                <Trans
                  id="common.open_documentation"
                  _={'Open documentation'}
                />
              }
              Component={Span}
              buttonProps={{ width: 'fit-content' }}
            >
              <Button
                type="primary"
                borderRadius={'20vh'}
                inverted
                iconType="documentation"
                onClick={onDocumentationButtonClick}
                px={3}
                py={1}
                ariaLabel={`open documentation - ${documentationLabel}`}
              >
                {documentationLabel}
              </Button>
            </Tooltip>
          ) : (
            documentationHref && (
              <DocumentationLink
                fontSize={2}
                iconSize={14}
                mb={[3, 0]}
                href={documentationHref}
                display="inline-block"
              >
                {documentationLabel ? (
                  documentationLabel
                ) : (
                  <Trans id="common.documentation" _={'Documentation'} />
                )}
              </DocumentationLink>
            )
          )}
        </Header>
        {control}
      </Div>
      <Section level={titlesCount} offset={maxPageTitles - titlesCount}>
        {children}
      </Section>
    </>
  );
};

PageHeader.displayName = 'PageHeader';

// firstPage is used when dealing with focus. When navigating the dash, focus
// jumps to the page content, but not when the dash is initially loaded.
let firstPage = '';

// firstLoad is used to ensure focus is handled correctly if the user navigates
// back to the first page that was loaded.
let firstLoad = true;

// Workaround for a bug where elements don't focus correctly.
const maxFocusAttempts = 10;
const focus = (el: HTMLElement | null, attempt: number = 0) => {
  el?.focus();
  if (
    typeof document !== 'undefined' &&
    document.activeElement !== el &&
    attempt < maxFocusAttempts
  ) {
    setTimeout(() => focus(el, attempt + 1), 10);
  }
};

const Page = ({
  title,
  parentPageLabel,
  description,
  documentationLabel,
  documentationHref,
  centerHeader,
  beta,
  testId,
  className,
  sidebar,
  type = 'wide',
  sidebarPosition = 'inside',
  autofocus = true,
  control,
  titleRef,
  parentPageLabelRef,
  children,
  navigation,
  onDocumentationButtonClick,
  documentationAsButton,
  ...props
}: Props) => {
  const skipTargetRef = useRef<HTMLAnchorElement>(null);
  const { pathname } = useLocation();

  useEffect(() => {
    // If autofocus is enabled, then focus will move to the title block when
    // the page is navigated to (but not when the dash is first loaded)
    if (autofocus) {
      if (!firstPage) {
        firstPage = pathname;
      } else if (firstPage !== pathname || !firstLoad) {
        focus(skipTargetRef.current);
        firstLoad = false;
      }
    }
  }, [pathname]);

  const sidebarInside = sidebarPosition === 'inside';

  return (
    <Main
      data-testid={testId}
      className={className}
      display={sidebar && sidebarInside ? undefined : 'flex'}
      py={4}
      mb={4}
      {...props}
    >
      <Div
        ml="auto"
        mr={sidebar && !sidebarInside ? 0 : 'auto'}
        display={
          sidebar && sidebarInside ? ['block', 'block', 'flex'] : undefined
        }
        width={type === 'unbounded' ? '100%' : '90%'}
        maxWidth={maxWidthByType[type] || maxWidthByType.narrow}
      >
        <Div
          width={sidebar && sidebarInside ? [1, 1, 2 / 3] : undefined}
          pr={sidebar && sidebarInside ? [0, 0, 3] : undefined}
          mt={0}
        >
          <a id="skipTarget" ref={skipTargetRef} tabIndex={-1} />

          <PageHeader
            title={title}
            parentPageLabel={parentPageLabel}
            description={description}
            documentationLabel={documentationLabel}
            documentationHref={documentationHref}
            centerHeader={centerHeader}
            control={control}
            children={children}
            beta={beta}
            titleRef={titleRef}
            parentPageLabelRef={parentPageLabelRef}
            navigation={navigation}
            onDocumentationButtonClick={onDocumentationButtonClick}
            documentationAsButton={documentationAsButton}
          />
        </Div>
        {sidebar && sidebarInside && (
          <Div width={[1, 1, 1 / 3]} pl={[0, 0, 3]} pt={[4, 4, 0]}>
            {sidebar}
          </Div>
        )}
      </Div>
      {!sidebarInside && sidebar}
    </Main>
  );
};

Page.displayName = 'Page';

export default createStyledComponent(() => {
  return {
    py: 4
  };
}, Page);
