"use client";

import * as React from "react";
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Typography } from "@/components/ui/typography";
import { XIcon } from "lucide-react";

function Dialog({ ...props }: DialogPrimitive.Root.Props) {
  return <DialogPrimitive.Root data-slot="dialog" {...props} />;
}

function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
  return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
}

function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
  return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
}

function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
  return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
}

function DialogOverlay({
  className,
  ...props
}: DialogPrimitive.Backdrop.Props) {
  return (
    <DialogPrimitive.Backdrop
      data-slot="dialog-overlay"
      className={cn(
        // No backdrop-filter: blurring the page behind a large calendar forces a
        // full re-rasterize on every open/close, which reads as a visual jerk.
        "fixed inset-0 isolate z-50 bg-black/20 duration-200 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
        className,
      )}
      {...props}
    />
  );
}

function DialogContent({
  className,
  children,
  showCloseButton = true,
  ...props
}: DialogPrimitive.Popup.Props & {
  showCloseButton?: boolean;
}) {
  return (
    <DialogPortal>
      <DialogOverlay />
      {/* Flex-centred wrapper instead of centring the popup with a translate:
          the enter/exit keyframes set `transform`, so a centring translate gets
          overwritten mid-animation and the dialog snaps into place (the
          "jerk"). Positioning here keeps the popup transform-free. */}
      <div className="pointer-events-none fixed inset-0 z-50 flex items-end justify-center sm:items-center sm:p-4">
        <DialogPrimitive.Popup
          data-slot="dialog-content"
          className={cn(
            // Mobile: bottom sheet — full-width, only as tall as its content
            // (capped), rounded top, safe-area aware.
            //
            // Column layout + `overflow-hidden`, NOT a scrolling box: the popup
            // itself must never scroll, or the title and the action buttons
            // scroll away with the content. `DialogBody` is the one scroll
            // region; header and footer stay pinned. Height is still auto, so
            // short dialogs size to their content and only tall ones hit the
            // cap and hand the overflow to the body.
            "pointer-events-auto relative flex max-h-[85svh] w-full flex-col gap-5 overflow-hidden rounded-t-2xl bg-popover p-5 pb-[max(1.25rem,env(safe-area-inset-bottom))] text-sm text-popover-foreground ring-1 ring-foreground/10 duration-200 outline-none",
            "data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
            "max-sm:data-open:slide-in-from-bottom-4 max-sm:data-closed:slide-out-to-bottom-4",
            // sm+: centred dialog
            "sm:max-w-md sm:gap-6 sm:rounded-xl sm:p-6 sm:pb-6",
            "sm:data-open:zoom-in-95 sm:data-closed:zoom-out-95",
            className,
          )}
          {...props}
        >
          {/* Grab affordance — signals the mobile bottom sheet */}
          <div
            aria-hidden
            className="absolute inset-x-0 top-2 mx-auto h-1 w-10 rounded-full bg-border sm:hidden"
          />
          {children}
          {showCloseButton && (
            <DialogPrimitive.Close
              data-slot="dialog-close"
              render={
                <Button
                  variant="ghost"
                  className="absolute top-4 inset-e-4"
                  size="icon-sm"
                />
              }
            >
              <XIcon />
              <span className="sr-only">Close</span>
            </DialogPrimitive.Close>
          )}
        </DialogPrimitive.Popup>
      </div>
    </DialogPortal>
  );
}

function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="dialog-header"
      // shrink-0: the header is pinned, it must not compress to make room for
      // a long body — the body scrolls instead.
      className={cn("flex shrink-0 flex-col gap-2", className)}
      {...props}
    />
  );
}

/**
 * The scrollable middle of a dialog. Everything between the header and the
 * footer goes in here.
 *
 * Optional — a dialog whose content can never outgrow the viewport works fine
 * without one. But once content CAN overflow, this is what keeps the title and
 * the action buttons on screen, so prefer it for any form or long-content
 * dialog.
 *
 * `min-h-0` is what actually makes it scroll: a flex child's default
 * `min-height: auto` refuses to shrink below its content, so the overflow would
 * escape to the popup (which clips it) instead of scrolling here.
 *
 * The scroll container sits inside the popup's padding, so content clips at the
 * body's own edge rather than bleeding to the popup border. Don't "fix" that
 * with a negative-margin bleed — the design system rules that out.
 */
function DialogBody({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="dialog-body"
      className={cn("min-h-0 flex-1 overflow-y-auto", className)}
      {...props}
    />
  );
}

function DialogFooter({
  className,
  showCloseButton = false,
  children,
  ...props
}: React.ComponentProps<"div"> & {
  showCloseButton?: boolean;
}) {
  return (
    <div
      data-slot="dialog-footer"
      // shrink-0: the actions stay reachable no matter how long the body is.
      className={cn(
        "flex shrink-0 flex-col-reverse gap-2 sm:flex-row sm:justify-end",
        className,
      )}
      {...props}
    >
      {children}
      {showCloseButton && (
        <DialogPrimitive.Close render={<Button variant="secondary" />}>
          Close
        </DialogPrimitive.Close>
      )}
    </div>
  );
}

function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
  return (
    <Typography
      as={DialogPrimitive.Title}
      data-slot="dialog-title"
      variant="h3"
      className={className}
      {...props}
    />
  );
}

function DialogDescription({
  className,
  ...props
}: DialogPrimitive.Description.Props) {
  return (
    <Typography
      as={DialogPrimitive.Description}
      data-slot="dialog-description"
      variant="body"
      color="secondary"
      className={cn(
        "*:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
        className,
      )}
      {...props}
    />
  );
}

export {
  Dialog,
  DialogBody,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogOverlay,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
};
