import React, { useLayoutEffect } from 'react'
import classNames from 'classnames'
import { DismissButton, Overlay, usePopover } from 'react-aria'
import { useSingleSelectContext } from '../../context'
import { type PopoverProps, type SelectItem } from '../../types'
import { usePositioningStyles, useSupportsAnchorPositioning } from './utils'

import styles from './Popover.module.css'

export const Popover = <T extends SelectItem>({
  state,
  popoverRef,
  children,
  clearButtonRef,
  ...restProps
}: PopoverProps<T>): React.ReactElement => {
  const { anchorName } = useSingleSelectContext()
  const manualPopoverRef = React.useRef<HTMLDivElement>(null)

  const { popoverProps } = usePopover(
    {
      ...restProps,
      popoverRef,
      shouldCloseOnInteractOutside: (element) => {
        if (clearButtonRef?.current?.contains(element)) {
          return false
        }
        return true
      },
    },
    state,
  )

  const supportsAnchorPositioning = useSupportsAnchorPositioning()
  const { popoverStyle, isPositioned, updatePosition } = usePositioningStyles(
    restProps.triggerRef as React.RefObject<HTMLElement>,
    manualPopoverRef,
    anchorName,
  )

  useLayoutEffect(() => {
    if (!supportsAnchorPositioning || !state.isOpen) return

    updatePosition()

    const popover = manualPopoverRef?.current

    if (popover?.showPopover) {
      popover.showPopover()
    }

    return () => {
      if (popover?.hidePopover) {
        popover.hidePopover()
      }
    }
  }, [state.isOpen, supportsAnchorPositioning, updatePosition, isPositioned])

  useLayoutEffect(() => {
    if (!supportsAnchorPositioning || state.isOpen) return

    const popover = manualPopoverRef?.current

    if (popover?.hidePopover) {
      popover.hidePopover()
    }
  }, [state.isOpen, supportsAnchorPositioning])

  const manualPopover = (
    <div
      // @ts-expect-error - popover attribute is not included in current ts version, ignore type error
      popover="manual"
      ref={manualPopoverRef}
      className={styles.popover}
      style={popoverStyle}
    >
      {children}
    </div>
  )

  return (
    <>
      {state.isOpen && (
        <Overlay>
          <div
            id="popover-id"
            {...popoverProps}
            ref={popoverRef}
            style={{
              ...popoverProps.style,
              ...(!supportsAnchorPositioning && {
                width: restProps.triggerRef.current?.getBoundingClientRect().width,
              }),
            }}
            className={classNames(styles.popover, {
              [styles.offsetSpacing]: !supportsAnchorPositioning,
            })}
          >
            <DismissButton onDismiss={state.close} />
            {supportsAnchorPositioning ? manualPopover : children}
            <DismissButton onDismiss={state.close} />
          </div>
        </Overlay>
      )}
    </>
  )
}
