import { ROOT_DATA } from '../../components/root';

type DVerticalSidePlacement = 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right';

interface DVerticalSidePosition {
  top: number;
  left: number;
  transformOrigin: string;
  arrowPosition: React.CSSProperties;
}

export function getVerticalSidePosition(
  targetEl: HTMLElement,
  popupSize: { width: number; height: number },
  config: {
    placement: DVerticalSidePlacement;
    offset?: number;
    inWindow?: number | false;
  }
): DVerticalSidePosition {
  const { width, height } = popupSize;
  const { placement, offset = 8, inWindow = false } = config;

  const targetRect = targetEl.getBoundingClientRect();

  const getPosition = (placement: DVerticalSidePlacement, prevPosition?: DVerticalSidePosition): DVerticalSidePosition => {
    let arrowPosition: React.CSSProperties = {};

    switch (placement) {
      case 'top':
        arrowPosition = {
          bottom: 0,
          left: '50%',
          transform: 'translate(-50%, 50%) rotate(45deg)',
        };
        break;

      case 'top-left':
        arrowPosition = {
          bottom: 0,
          left: 20,
          transform: 'translate(0, 50%) rotate(45deg)',
        };
        break;

      case 'top-right':
        arrowPosition = {
          right: 20,
          bottom: 0,
          transform: 'translate(0, 50%) rotate(45deg)',
        };
        break;

      case 'bottom':
        arrowPosition = {
          top: 0,
          left: '50%',
          transform: 'translate(-50%, -50%) rotate(45deg)',
        };
        break;

      case 'bottom-left':
        arrowPosition = {
          top: 0,
          left: 20,
          transform: 'translate(0, -50%) rotate(45deg)',
        };
        break;

      case 'bottom-right':
        arrowPosition = {
          top: 0,
          right: 20,
          transform: 'translate(0, -50%) rotate(45deg)',
        };
        break;

      default:
        break;
    }

    let top =
      placement === 'top' || placement === 'top-left' || placement === 'top-right'
        ? targetRect.top - height - offset
        : targetRect.top + targetRect.height + offset;
    if (inWindow !== false) {
      top = Math.min(Math.max(top, inWindow), ROOT_DATA.pageSize.height - height - inWindow);
    }

    let left =
      placement === 'top' || placement === 'bottom'
        ? targetRect.left + (targetRect.width - width) / 2
        : placement === 'top-left' || placement === 'bottom-left'
        ? targetRect.left
        : targetRect.left + targetRect.width - width;
    if (inWindow !== false) {
      left = Math.min(Math.max(left, inWindow), window.screen.availWidth - width - inWindow);
    }

    const transformOrigin = placement === 'top' || placement === 'top-left' || placement === 'top-right' ? 'center bottom' : 'center top';

    const position = {
      top,
      left,
      transformOrigin,
      arrowPosition,
    };

    if (
      inWindow !== false &&
      ((placement.includes('top') && top === inWindow) ||
        (placement.includes('bottom') && top === ROOT_DATA.pageSize.height - height - inWindow))
    ) {
      if (prevPosition) {
        return prevPosition;
      } else {
        return getPosition(
          placement.includes('top')
            ? (placement.replace('top', 'bottom') as DVerticalSidePlacement)
            : (placement.replace('bottom', 'top') as DVerticalSidePlacement),
          position
        );
      }
    }

    return position;
  };

  return getPosition(placement);
}