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

import type { WithConditions } from '@redocly/config';

import {
  CodeWalkthroughControlsStateContext,
  CodeWalkthroughStepsContext,
} from '@redocly/theme/core/contexts';

export type CodeStepProps = WithConditions<{
  id: string;
  stepKey: number;
  heading?: string;
}>;

export function CodeStep({
  id,
  heading,
  stepKey,
  when,
  unless,
  children,
}: PropsWithChildren<CodeStepProps>) {
  const compRef = useRef<HTMLDivElement | null>(null);
  const { areConditionsMet } = useContext(CodeWalkthroughControlsStateContext);
  const { activeStep, setActiveStep, register, unregister, lockObserver, filtersElementRef } =
    useContext(CodeWalkthroughStepsContext);
  const isActive = activeStep === id;

  const [scrollMarginTop, setScrollMarginTop] = useState(0);

  const handleActivateStep = () => {
    if (lockObserver) {
      lockObserver.current = true;

      if (compRef.current) {
        compRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }

      setActiveStep(id);
      setTimeout(() => {
        lockObserver.current = false;
      }, 1000);
    }
  };

  useEffect(() => {
    // If the step is active during first render, scroll to it
    // This is to ensure that the step is visible when the page is loaded
    if (isActive) {
      // Ensure scrollMarginTop calculated before step being scrolled.
      setTimeout(handleActivateStep, 5);
    }

    // Ignore dependency array because we only need to run this once
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    const currentCompRef = compRef.current;
    if (currentCompRef) {
      currentCompRef
        .querySelectorAll<HTMLElement>('a, button, input, textarea, select, [tabindex]')
        .forEach((el) => {
          el.setAttribute('tabindex', '-1');
        });

      register(currentCompRef);
    }

    const filtersElementHeight = filtersElementRef?.current?.clientHeight || 0;
    const navbarHeight = document.querySelector('nav')?.clientHeight || 0;
    setScrollMarginTop(filtersElementHeight + navbarHeight + 10);

    return () => {
      if (currentCompRef) {
        unregister(currentCompRef);
      }
    };
  }, [activeStep, register, unregister, filtersElementRef]);

  if (!areConditionsMet({ when, unless })) {
    if (isActive) {
      setActiveStep(null);
    }
    return null;
  }

  return (
    <StepWrapper
      data-component-name="Markdoc/CodeWalkthrough/CodeStep"
      ref={compRef}
      isActive={isActive}
      scrollMarginTop={scrollMarginTop}
      data-step-key={stepKey}
      data-step-active={isActive}
      onClick={handleActivateStep}
      onFocus={handleActivateStep}
      tabIndex={0}
      className="code-step-wrapper"
    >
      <StepContent isActive={isActive}>
        {heading ? <StepHeading>{heading}</StepHeading> : null}
        {children}
      </StepContent>
    </StepWrapper>
  );
}

const StepContent = styled.div<{ isActive: boolean }>`
  margin: var(--spacing-xs) 0px var(--spacing-xs) calc(var(--spacing-unit) * 3.5);
  padding: var(--spacing-md) var(--spacing-lg);
  background: ${({ isActive }) => (isActive ? 'var(--layer-color)' : 'none')};
  border-radius: var(--border-radius);

  &:hover {
    background-color: ${({ isActive }) =>
      isActive ? 'var(--code-step-bg-active-hover)' : 'var(--code-step-bg-hover)'};
  }
`;

const StepHeading = styled.p`
  font-weight: var(--font-weight-semibold);
`;

export const StepWrapper = styled.div<{ isActive: boolean; scrollMarginTop: number }>`
  position: relative;
  scroll-margin-top: ${({ scrollMarginTop }) => scrollMarginTop}px;

  &::before {
    content: '';
    position: absolute;
    width: 6px;
    height: 100%;
    background-color: ${({ isActive }) =>
      isActive ? 'var(--code-step-vertical-line-bg-active)' : 'none'};
    border-radius: var(--border-radius-lg);
  }
  &:hover::before {
    background-color: ${({ isActive }) =>
      isActive
        ? 'var(--code-step-vertical-line-bg-active)'
        : 'var(--code-step-vertical-line-bg-hover)'};
  }

  &:hover::before {
    width: ${({ isActive }) => (isActive ? '8px' : '6px')};
  }

  &:hover ${StepContent} {
    background-color: ${({ isActive }) =>
      isActive ? 'var(--code-step-bg-active-hover)' : 'var(--code-step-bg-hover)'};
  }
`;
