import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "lucide-react"
import type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes, ReactNode } from "react"
import { forwardRef, useCallback } from "react"

import { cn } from "../../utils/cn.ts"
import { Text } from "../text/text.tsx"

const Dialog = DialogPrimitive.Root
const DialogTrigger = DialogPrimitive.Trigger
const DialogPortal = DialogPrimitive.Portal
const DialogClose = DialogPrimitive.Close

const DialogOverlay = forwardRef<
  ElementRef<typeof DialogPrimitive.Overlay>,
  ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className: _cn, ...props }, ref) => (
  <DialogPrimitive.Overlay
    ref={ref}
    className={cn(
      "fixed inset-0 z-50 bg-white/60 dark:bg-black/60 backdrop-blur-sm backdrop-saturate-200",
      "data-[state=open]:animate-in data-[state=closed]:animate-out",
      "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
    )}
    {...props}
  />
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName

export type DialogContentProps = Omit<
  ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,
  "onEscapeKeyDown" | "onPointerDownOutside" | "onInteractOutside"
> & {
  dismissible: boolean
  height?: "content" | "screen"
}

const DialogContent = forwardRef<ElementRef<typeof DialogPrimitive.Content>, DialogContentProps>(
  ({ className: _cn, children, forceMount, dismissible = false, height = "content", ...props }, ref) => {
    const onEscapeKeyDown = useCallback(
      (event: KeyboardEvent) => {
        if (dismissible) return
        event.preventDefault()
      },
      [dismissible],
    )
    const onPointerDownOutside = useCallback(
      (event: CustomEvent<{ originalEvent: PointerEvent }>) => {
        if (dismissible) return
        event.preventDefault()
      },
      [dismissible],
    )
    const onInteractOutside = useCallback(
      (event: CustomEvent<{ originalEvent: Event }>) => {
        if (dismissible) return
        event.preventDefault()
      },
      [dismissible],
    )
    return (
      <DialogPortal>
        {forceMount ? <DialogOverlay forceMount /> : <DialogOverlay />}
        <DialogPrimitive.Content
          ref={ref}
          {...(forceMount ? { forceMount: true as const } : {})}
          className={cn(
            "fixed left-1/2 top-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 bg-background shadow-lg rounded-2xl duration-200",
            "data-[state=open]:animate-in data-[state=closed]:animate-out",
            "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
            "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
            _cn,
            {
              "max-h-[90%] border dark:border": height === "content",
              "h-[96%]": height === "screen",
            },
          )}
          onEscapeKeyDown={onEscapeKeyDown}
          onPointerDownOutside={onPointerDownOutside}
          onInteractOutside={onInteractOutside}
          {...props}
        >
          {children}
          {dismissible ? (
            <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
              <X className="h-4 w-4" />
              <span className="sr-only">Close</span>
            </DialogPrimitive.Close>
          ) : null}
        </DialogPrimitive.Content>
      </DialogPortal>
    )
  },
)
DialogContent.displayName = DialogPrimitive.Content.displayName

const DialogHeader = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
  <div className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...props} />
)
DialogHeader.displayName = "DialogHeader"

export type FooterProps = {
  children: ReactNode
  align?: "right" | "justify"
}
const DialogFooter = ({ children, align = "right" }: FooterProps) => (
  <div
    className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", {
      "sm:justify-end": align === "right",
      "sm:justify-between": align === "justify",
    })}
  >
    {children}
  </div>
)
DialogFooter.displayName = "DialogFooter"

type DialogTitleProps = Omit<ComponentPropsWithoutRef<typeof DialogPrimitive.Title>, "className">
const DialogTitle = forwardRef<ElementRef<typeof DialogPrimitive.Title>, DialogTitleProps>(
  ({ children, ...props }, ref) => (
    <DialogPrimitive.Title ref={ref} {...props}>
      <Text.H4 weight="medium">{children}</Text.H4>
    </DialogPrimitive.Title>
  ),
)
DialogTitle.displayName = DialogPrimitive.Title.displayName

type DialogDescriptionProps = Omit<ComponentPropsWithoutRef<typeof DialogPrimitive.Description>, "className">
const DialogDescription = forwardRef<ElementRef<typeof DialogPrimitive.Description>, DialogDescriptionProps>(
  ({ children, ...props }, ref) => (
    <DialogPrimitive.Description ref={ref} className="text-sm text-muted-foreground" {...props}>
      <Text.H5 color="foregroundMuted">{children}</Text.H5>
    </DialogPrimitive.Description>
  ),
)
DialogDescription.displayName = DialogPrimitive.Description.displayName

export { Dialog, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription }
