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

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

const InDialogContext = React.createContext<boolean>(false);
export const useInDialog = () => React.use(InDialogContext);

const DialogContext = React.createContext<
  React.ComponentPropsWithRef<typeof DialogPrimitive.DialogOverlay>
>({});
export function Dialog({
  children,
  preview,
  onOpenChange,
  ...rest
}: DialogPrimitive.DialogProps & {
  className?: string;
  children: React.ReactNode;
  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 (
    <DialogPrimitive.Root
      open={preview || isOpen}
      onOpenChange={(isOpen) => {
        setState({ isOpen }, process.env.PREVIEW ? `onChange` : undefined);
        onOpenChange?.(isOpen);
      }}
    >
      <DialogContext value={rest}>{children}</DialogContext>
    </DialogPrimitive.Root>
  );
}

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

const DialogOverlay = ({
  className,
  ...props
}: React.ComponentPropsWithRef<typeof DialogPrimitive.DialogOverlay>) => (
  <DialogPrimitive.Overlay
    className={clsx("__dialog_overlay", styles.overlay, className)}
    {...props}
  />
);
Dialog.DialogOverlay = DialogOverlay;

const DialogContent = ({
  size = "md",
  className,
  children,
  autoFocus = true,
  ...props
}: React.ComponentPropsWithRef<typeof DialogPrimitive.Content> & {
  autoFocus: boolean;
  size: "sm" | "md" | "lg" | "xl" | "full";
}) => {
  const additionalProps: Partial<
    React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
  > = {};
  if (!autoFocus) {
    additionalProps.onOpenAutoFocus = block;
    additionalProps.onCloseAutoFocus = block;
    additionalProps.onPointerDownOutside = block;
    additionalProps.onInteractOutside = block;
  }
  const overlayProps = React.useContext(DialogContext);
  return (
    <DialogPrimitive.Portal>
      <DialogOverlay {...overlayProps} />
      <DialogPrimitive.Content
        className={clsx("__dialog_content", styles.content, className)}
        {...additionalProps}
        {...props}
        data-size={size}
      >
        <InDialogContext value={true}>{children}</InDialogContext>
      </DialogPrimitive.Content>
    </DialogPrimitive.Portal>
  );
};
Dialog.DialogContent = DialogContent;

DialogContent.DialogClose = ({
  className,
  children,
  ...props
}: DialogPrimitive.DialogCloseProps) => {
  const child =
    props.asChild === false ? children : React.Children.toArray(children)?.[0];
  return (
    <ButtonContext value={true}>
      <DialogPrimitive.Close
        className={clsx("__dialog_close", className)}
        asChild
        {...props}
      >
        {child}
      </DialogPrimitive.Close>
    </ButtonContext>
  );
};

DialogContent.DialogHeader = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div className={clsx("__dialog_header", className)} {...props} />
);

DialogContent.DialogFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div className={clsx("__dialog_footer", className)} {...props} />
);

DialogContent.DialogTitle = ({
  className,
  ...props
}: React.ComponentPropsWithRef<typeof DialogPrimitive.DialogTitle>) => (
  <DialogPrimitive.Title
    className={clsx("__dialog_title", className)}
    {...props}
  />
);

DialogContent.DialogDescription = ({
  className,
  ...props
}: React.ComponentPropsWithRef<typeof DialogPrimitive.DialogDescription>) => (
  <DialogPrimitive.Description
    className={clsx("__dialog_description", className)}
    {...props}
  />
);

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