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

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

import {
  useActiveHeading,
  useThemeHooks,
  useThemeConfig,
  useFullHeight,
} from '@redocly/theme/core/hooks';
import {
  breakpoints,
  getDisplayedHeadingsIds,
  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 activeHeadingId = useActiveHeading(
    contentWrapper,
    getDisplayedHeadingsIds(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={activeHeadingId === heading.id ? 'active' : ''}
                dangerouslySetInnerHTML={{ __html: heading.value || '' }}
                data-testid={`toc-${heading.value}`}
                onClick={() => telemetry.send('toc_item_clicked', {})}
              />
            );
          })}
        </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);
  }

  :empty {
    padding: 0;
  }
`;
