import React, { useContext, useRef, useEffect, useState } from 'react';
import styled, { css } from 'styled-components';

import type { JSX } from 'react';

import { CodeWalkthroughStepsContext } from '@redocly/theme/core/contexts';
import { CodeBlockContainer } from '@redocly/theme/components/CodeBlock/CodeBlockContainer';

export type CodeContainerProps = {
  highlightedCode: string;
  toolbar: JSX.Element;
};

export function CodeContainer({
  highlightedCode,
  toolbar,
}: CodeContainerProps): JSX.Element | null {
  const { activeStep } = useContext(CodeWalkthroughStepsContext);
  const [isHovered, setIsHovered] = useState(false);
  const compRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    // useEffect executed before DOM is updated due to re-render called before "painting" phase.
    setTimeout(() => {
      if (compRef.current) {
        const highlightedLines = Array.from(
          compRef.current.querySelectorAll('span.line.highlighted'),
        );
        const { bottom: panelBottom, top: panelTop } = compRef.current.getBoundingClientRect();

        const linesBelow: Element[] = [];
        const linesAbove: Element[] = [];
        for (const highlightedLine of highlightedLines) {
          const { bottom: lineBottom, top: lineTop } = highlightedLine.getBoundingClientRect();
          const below = lineBottom > panelBottom;
          const above = lineTop < panelTop;

          if (below) {
            linesBelow.push(highlightedLine);
          } else if (above) {
            linesAbove.push(highlightedLine);
          }
        }

        if ((linesBelow.length && linesAbove.length) || linesAbove.length) {
          linesAbove[0].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
        } else if (linesBelow.length) {
          linesBelow[linesBelow.length - 1].scrollIntoView({
            behavior: 'smooth',
            block: 'nearest',
            inline: 'start',
          });
        }
      }
    }, 200);
  }, [activeStep]);

  return (
    <CodeContainerWrapper
      data-component-name="Markdoc/CodeWalkthrough/CodeContainer"
      ref={compRef}
      hideCodeColors={!isHovered}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      <CodeBlockContainer dangerouslySetInnerHTML={{ __html: highlightedCode }} />
      {toolbar}
    </CodeContainerWrapper>
  );
}

const CodeContainerWrapper = styled.div<{ hideCodeColors?: boolean }>`
  position: relative;

  display: flex;
  flex-direction: column;
  flex-grow: 1;
  min-height: 0;

  pre {
    display: grid;
    grid-auto-rows: min-content;
    min-height: 0;
    overflow: scroll;
    margin: 0 !important;
    height: 100%;
    padding-left: 0 !important;

    span.line::before {
      color: var(--code-panel-line-numbering-color);
    }
    ${({ hideCodeColors }) =>
      hideCodeColors &&
      css`
        .line.greyed-out {
          color: var(--text-color-helper) !important;
          * {
            color: var(--text-color-helper) !important;
          }
        }
      `}
  }
`;
