import React, { useState } from 'react';
import { useFloating, offset, shift, flip, arrow, Placement, Middleware } from '@floating-ui/react';

export type PopoverProps = {
  title?: React.ReactNode;
  content: React.ReactNode;
  placement?: Placement;
  children: React.ReactElement;
  className?: string;
};

/**
 * Popover using floating-ui. Controlled by hover/focus.
 */
export function Popover({ title, content, placement = 'top', children, className = '' }: PopoverProps) {
  const [open, setOpen] = useState(false);
  const [arrowEl, setArrowEl] = useState<HTMLElement | null>(null);

  const middleware: Middleware[] = [offset(8), flip(), shift()];
  if (arrowEl) middleware.push(arrow({ element: arrowEl }));

  const { x, y, refs, strategy, middlewareData, placement: finalPlacement } = useFloating({
    open,
    onOpenChange: setOpen,
    placement,
    middleware
  });

  const staticSide = {
    top: 'bottom',
    right: 'left',
    bottom: 'top',
    left: 'right'
  }[finalPlacement.split('-')[0]] as string;

  return (
    <>
      {React.cloneElement(children, {
        ref: refs.setReference,
        onMouseEnter: () => setOpen(true),
        onMouseLeave: () => setOpen(false),
        onFocus: () => setOpen(true),
        onBlur: () => setOpen(false)
      })}
      {open ? (
        <div
          ref={refs.setFloating}
          className={['popover bs-popover-auto show', className].filter(Boolean).join(' ')}
          role="tooltip"
          style={{
            position: strategy,
            top: y ?? 0,
            left: x ?? 0
          }}
        >
          {title ? (
            <div className="popover-header">
              {title}
              <button type="button" className="btn-close float-end" aria-label="Close" onClick={() => setOpen(false)} />
            </div>
          ) : null}
          <div className="popover-body">{content}</div>
          <div
            ref={setArrowEl as any}
            className="popover-arrow"
            style={{
              left: middlewareData.arrow?.x,
              top: middlewareData.arrow?.y,
              [staticSide]: '-4px'
            }}
          />
        </div>
      ) : null}
    </>
  );
}
