import * as React from 'react';
import styled from 'styled-components';

import type { JSX } from 'react';
import type { MdHeading } from '@redocly/theme/core/types';

import {
  useActiveHeading,
  useThemeHooks,
  useThemeConfig,
  useFullHeight,
} from '@redocly/theme/core/hooks';
import { breakpoints, getDisplayedHeadings, getLeastDepth } from '@redocly/theme/core/utils';

export type TableOfContentProps = {
  headings?: Array<MdHeading | null> | null | undefined;
  contentWrapper: HTMLDivElement | null;
  className?: string;
};

export function TableOfContent(props: TableOfContentProps): JSX.Element | null {
  const { headings, contentWrapper, className } = props;
  const { useTranslate, useTelemetry } = useThemeHooks();
  const { translate } = useTranslate();
  const telemetry = useTelemetry();

  const sidebar = React.useRef<HTMLDivElement | null>(null);
  useFullHeight(sidebar);
  const { markdown: { toc = {} } = {} } = useThemeConfig();

  const displayedHeadings = getDisplayedHeadings(headings, toc.depth || 3);
  const leastDepth = getLeastDepth(displayedHeadings);
  const { heading: activeHeading, handleHeadingClick } = useActiveHeading(
    contentWrapper,
    displayedHeadings,
  );

  if (toc?.hide) {
    return null;
  }

  return (
    <TableOfContentMenu data-component-name="TableOfContent/TableOfContent" className={className}>
      <TableOfContentItems ref={sidebar}>
        {displayedHeadings.length ? (
          <TableOfContentHeader data-translation-key="toc.header">
            {translate('toc.header', toc.header || 'On this page')}
          </TableOfContentHeader>
        ) : null}
        {displayedHeadings.map((heading: MdHeading | null, idx: number) => {
          if (!heading) {
            return null;
          }
          const href = '#' + heading.id;
          return (
            <TableOfContentMenuItem
              key={href + idx}
              href={href}
              depth={heading.depth - leastDepth + 1 || 0}
              className={activeHeading === heading.id ? 'active' : ''}
              dangerouslySetInnerHTML={{ __html: heading.value || '' }}
              data-testid={`toc-${heading.value}`}
              onClick={(e) => {
                e.preventDefault();
                telemetry.sendTocItemClickedMessage();
                handleHeadingClick(heading.id);
              }}
            />
          );
        })}
      </TableOfContentItems>
    </TableOfContentMenu>
  );
}

const TableOfContentMenu = styled.aside`
  background-color: var(--toc-bg-color);
  flex-shrink: 0;
  display: none !important;

  @media screen and (min-width: ${breakpoints.medium}) {
    width: var(--toc-width);
    display: block !important;
  }
`;

const TableOfContentHeader = styled.div`
  font-family: var(--toc-heading-font-family);
  font-size: var(--toc-heading-font-size);
  font-weight: var(--toc-heading-font-weight);
  padding: var(--toc-item-padding-vertical) var(--toc-item-padding-horizontal);
  color: var(--toc-heading-text-color);
  text-transform: var(--toc-heading-text-transform);
  line-height: var(--toc-heading-line-height);
`;

const TableOfContentItems = styled.div`
  position: sticky;
  top: calc(var(--navbar-height) + var(--toc-offset-top));
  max-height: calc(100vh - var(--navbar-height) - var(--toc-offset-top));
  overflow-y: auto;
  width: var(--toc-width);
  border-left: solid 1px var(--toc-border-color);
`;

const TableOfContentMenuItem = styled.a<{ depth: number }>`
  display: block;
  color: var(--toc-item-text-color);
  font-weight: var(--toc-item-font-weight);
  background-color: var(--toc-item-bg-color);
  cursor: pointer;
  font-size: var(--toc-item-font-size);
  padding: var(--toc-item-padding-vertical) var(--toc-item-padding-horizontal);
  padding-left: calc(var(--toc-item-nested-offset) * ${({ depth }) => depth});
  transition:
    background-color 0.3s,
    color 0.3s;
  text-decoration: none;
  word-break: break-word;
  font-family: var(--heading-font-family, var(--toc-item-font-family));
  line-height: var(--toc-item-line-height);

  border-left: solid 2px transparent;

  :hover {
    color: var(--toc-item-text-color-active);
  }
  &.active {
    color: var(--toc-item-text-color-active);
    border-left: solid 2px var(--toc-item-border-color-active);
    font-weight: var(--toc-item-font-weight-active);
  }

  :empty {
    padding: 0;
  }
`;
