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 SheetContext = React.createContext<
  React.ComponentPropsWithRef<typeof DialogPrimitive.DialogOverlay>
>({});

export function Sheet({
  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);
      }}
    >
      <SheetContext value={rest}>{children}</SheetContext>
    </DialogPrimitive.Root>
  );
}

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

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

const SheetContent = ({
  side = "right",
  className,
  children,
  autoFocus = true,
  ...props
}: React.ComponentPropsWithRef<typeof DialogPrimitive.Content> & {
  autoFocus: boolean;
  side: "top" | "right" | "bottom" | "left";
}) => {
  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(SheetContext);
  return (
    <DialogPrimitive.Portal>
      <SheetOverlay {...overlayProps} />
      <DialogPrimitive.Content
        className={clsx("__sheet_content", styles.content, className)}
        {...additionalProps}
        {...props}
        data-side={side}
      >
        {children}
      </DialogPrimitive.Content>
    </DialogPrimitive.Portal>
  );
};
Sheet.SheetContent = SheetContent;

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

SheetContent.SheetHeader = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div className={clsx("__sheet_header", className)} {...props} />
);

SheetContent.SheetFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div className={clsx("__sheet_footer", className)} {...props} />
);

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

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

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