import { useLayoutEffect, useRef, useState } from 'react';

import type { RefObject } from 'react';
import type { TooltipPlacement, TooltipProps } from '@redocly/theme/core/types';

type TooltipFallbackPlacementParams = {
  isOpened: boolean;
  placement: TooltipPlacement;
  arrowPosition: TooltipProps['arrowPosition'];
  fallbackPlacements: TooltipPlacement[] | undefined;
  tooltipBodyRef: RefObject<HTMLElement | null>;
};

type TooltipFallbackPlacementResult = {
  activePlacement: TooltipPlacement;
  activeArrowPosition: TooltipProps['arrowPosition'];
};

export function useTooltipFallbackPlacement({
  isOpened,
  placement,
  arrowPosition,
  fallbackPlacements,
  tooltipBodyRef,
}: TooltipFallbackPlacementParams): TooltipFallbackPlacementResult {
  const [activePlacement, setActivePlacement] = useState<TooltipPlacement>(placement);
  const wasOpenRef = useRef(false);
  const candidateIndexRef = useRef(0);

  useLayoutEffect(() => {
    if (!isOpened) {
      wasOpenRef.current = false;
      candidateIndexRef.current = 0;
      return;
    }

    if (!wasOpenRef.current) {
      wasOpenRef.current = true;
      candidateIndexRef.current = 0;
      if (activePlacement !== placement) {
        setActivePlacement(placement);
        return;
      }
    }

    if (!tooltipBodyRef.current || !fallbackPlacements?.length) return;

    const candidates: TooltipPlacement[] = [placement, ...fallbackPlacements];

    if (candidateIndexRef.current >= candidates.length) return;

    const rect = tooltipBodyRef.current.getBoundingClientRect();
    const overflows =
      rect.left < 0 ||
      rect.top < 0 ||
      rect.right > window.innerWidth ||
      rect.bottom > window.innerHeight;

    if (!overflows) return;

    candidateIndexRef.current++;

    if (candidateIndexRef.current < candidates.length) {
      setActivePlacement(candidates[candidateIndexRef.current]);
    } else if (activePlacement !== placement) {
      setActivePlacement(placement);
    }
  }, [isOpened, activePlacement, placement, fallbackPlacements, tooltipBodyRef]);

  const activeArrowPosition = activePlacement === placement ? arrowPosition : 'center';

  return { activePlacement, activeArrowPosition };
}
