import React, { createElement, isValidElement } from 'react';
import styled from 'styled-components';
import { useLocation } from 'react-router-dom';

import type { JSX, PropsWithChildren, ReactElement, ReactNode } from 'react';

import { Image as MarkdocImage } from '@redocly/theme/markdoc/components/Image/Image';
import { concatClassNames } from '@redocly/theme/core/utils';
import { LinkIcon } from '@redocly/theme/icons/LinkIcon/LinkIcon';
import { PageActions } from '@redocly/theme/components/PageActions/PageActions';
import { useThemeHooks } from '@redocly/theme/core/hooks';
import {
  ANCHOR_CLASS,
  HEADING_ANCHOR_CLASS,
  HEADING_CLASS_PREFIX,
  MARKDOWN_CLASS_NAME,
} from '@redocly/theme/core/constants';

function renderWithSpanWrapper(children: ReactNode): ReactNode {
  const childrenArray = React.Children.toArray(children);

  if (childrenArray.length === 0) return null;

  const first = childrenArray[0];
  const last = childrenArray[childrenArray.length - 1];

  // Check if an element is an <img> or the Markdoc Image component
  const isImage = (node: ReactNode): node is ReactElement => {
    if (!isValidElement(node)) return false;
    if (typeof node.type === 'string') return node.type === 'img';
    return node.type === MarkdocImage;
  };

  const middleChildren = childrenArray.slice(
    isImage(first) ? 1 : 0,
    isImage(last) ? childrenArray.length - 1 : childrenArray.length,
  );

  return (
    <>
      {isImage(first) && first}
      {middleChildren.length > 0 && <StyledHeadingText>{middleChildren}</StyledHeadingText>}
      {isImage(last) && last}
    </>
  );
}

export function Heading({
  level,
  id,
  children,
  'data-source': dataSource,
  'data-hash': dataHash,
  className,
  __idx,
}: PropsWithChildren<{
  level: number;
  id: string;
  'data-source'?: string;
  'data-hash'?: string;
  className?: string;
  __idx?: number;
}>): JSX.Element {
  const { pathname } = useLocation();
  const { usePageProps } = useThemeHooks();
  const pageProps = usePageProps();

  const isMarkdownPage =
    pageProps?.metadata?.type === 'markdown' || pageProps?.metadata?.type === 'asciidoc';
  const headingTextId = `${id}-heading-text`;

  const linkEl = (
    <a
      aria-labelledby={headingTextId}
      href={`#${id}`}
      className={concatClassNames(ANCHOR_CLASS, 'before')}
    >
      <LinkIcon aria-hidden="true" focusable="false" color="--heading-anchor-color" />
    </a>
  );

  const headingText = createElement(
    `h${level}`,
    { id: headingTextId },
    renderWithSpanWrapper(children),
  );

  return (
    <div
      id={id}
      className={concatClassNames(
        HEADING_ANCHOR_CLASS,
        MARKDOWN_CLASS_NAME,
        `${HEADING_CLASS_PREFIX}-${level}`,
        className,
      )}
      data-component-name="Markdoc/Heading/Heading"
      data-source={dataSource}
      data-hash={dataHash}
    >
      <HeadingContentWrapper>
        {linkEl}
        {headingText}
        {isMarkdownPage && __idx === 0 ? <PageActions pageSlug={pathname} /> : null}
      </HeadingContentWrapper>
    </div>
  );
}

const HeadingContentWrapper = styled.div`
  display: flex;
  gap: var(--spacing-xs);

  & > .${ANCHOR_CLASS} {
    display: flex;
    align-items: center;
    height: 1lh;
  }

  &:has([data-component-name='PageActions/PageActions']:hover) {
    && .${ANCHOR_CLASS} svg {
      visibility: hidden;
    }
  }
`;

const StyledHeadingText = styled.span`
  margin: auto 0;
  && > img:only-child {
    display: inline-block;
  }
`;
