import clsx from "clsx";
import { Popover as PopoverPrimitive } from "radix-ui";
import * as React from "react";
import { useEvent, useGetKey, useGetSet } from "../../hooks";

import { useInDialog } from "../Dialog";
import { ButtonContext } from "../Link";
import * as styles from "./styles.module.css";

export function Popover({
  className,
  children,
  preview,
  onOpenChange,
  ...rest
}: PopoverPrimitive.PopoverProps & {
  className?: string;
  preview?: true;
  "data-id": string;
}) {
  const key = useGetKey(rest);
  const [{ isOpen }, setState] = useGetSet(key, { isOpen: false }, true);
  const open = React.useCallback(() => {
    setState({ isOpen: true }, process.env.PREVIEW ? `onChange` : undefined);
  }, [setState]);
  const close = React.useCallback(() => {
    setState({ isOpen: false }, process.env.PREVIEW ? `onChange` : undefined);
  }, [setState]);
  const id = rest["data-id"];
  useEvent(id, "open", open);
  useEvent(id, "close", close);
  return (
    <div
      className={clsx("__popover", styles.root, className)}
      data-component="Popover$Brevity"
      {...rest}
    >
      <PopoverPrimitive.Root
        open={preview || isOpen}
        onOpenChange={(isOpen) => {
          setState({ isOpen }, process.env.PREVIEW ? `onChange` : undefined);
          onOpenChange?.(isOpen);
        }}
      >
        {children}
      </PopoverPrimitive.Root>
    </div>
  );
}

Popover.PopoverTrigger = ({
  children,
  className,
  ...props
}: React.ComponentPropsWithRef<typeof PopoverPrimitive.Trigger>) => {
  const child =
    props.asChild === false ? children : React.Children.toArray(children)?.[0];
  return (
    <PopoverPrimitive.Trigger
      className={clsx("__popover_trigger", className)}
      asChild
      {...props}
    >
      {child}
    </PopoverPrimitive.Trigger>
  );
};

Popover.PopoverClose = ({
  className,
  children,
  ...props
}: PopoverPrimitive.PopoverCloseProps) => {
  const child =
    props.asChild === false ? children : React.Children.toArray(children)?.[0];
  return (
    <ButtonContext value={true}>
      <PopoverPrimitive.Close
        className={clsx("__popover_close", className)}
        asChild
        {...props}
      >
        {child}
      </PopoverPrimitive.Close>
    </ButtonContext>
  );
};

Popover.PopoverContent = ({
  className,
  children,
  autoFocus = true,
  align = "center",
  sideOffset = 4,
  ...props
}: PopoverPrimitive.PopoverContentProps) => {
  const additionalProps: Partial<
    React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
  > = {};
  const inDialog = useInDialog();
  if (!autoFocus) {
    additionalProps.onOpenAutoFocus = block;
    additionalProps.onCloseAutoFocus = block;
    additionalProps.onPointerDownOutside = block;
    additionalProps.onInteractOutside = block;
  }
  if (inDialog) {
    additionalProps.onWheel = (e) => e.stopPropagation();
    additionalProps.onTouchMove = (e) => e.stopPropagation();
  }
  return (
    <PopoverPrimitive.Portal>
      <PopoverPrimitive.Content
        align={align}
        sideOffset={sideOffset}
        className={clsx("__popover_content", styles.content, className)}
        {...additionalProps}
        {...props}
      >
        {children}
      </PopoverPrimitive.Content>
    </PopoverPrimitive.Portal>
  );
};

Popover.PopoverAnchor = PopoverPrimitive.Anchor;
Popover.PopoverArrow = PopoverPrimitive.Arrow;

function block(e: Event) {
  e?.preventDefault();
}
