// @design-system: overlays/Dialog
// Registered at /design-system#dialog-overlay - Phase 3 (Agent 3E) will render the gallery.

import * as RadixDialog from '@radix-ui/react-dialog';
import { X } from 'lucide-react';
import { useEffect, type ReactNode } from 'react';
import { cn } from '@/lib/cn';
import { useT } from '@/lib/i18n/react';

// ─── Root + Trigger ────────────────────────────────────────────────────────

/** Root dialog controller. */
export const Dialog = RadixDialog.Root;

/** Trigger element for opening the dialog. */
export const DialogTrigger = RadixDialog.Trigger;

/** Portal wrapper (internal use — not exported). */
const DialogPortal = RadixDialog.Portal;

// ─── Overlay ──────────────────────────────────────────────────────────────

/** Props for DialogOverlay (internal use — not exported). */
type DialogOverlayProps = React.ComponentPropsWithoutRef<typeof RadixDialog.Overlay>;

/** Semi-transparent backdrop (internal use — not exported). */
function DialogOverlay({ className, ...props }: DialogOverlayProps) {
  return (
    <RadixDialog.Overlay
      data-motion-role="overlay"
      className={cn(
        'z-overlay bg-surface-overlay fixed inset-0',
        'motion-overlay-enter motion-overlay-exit',
        className,
      )}
      {...props}
    />
  );
}

// ─── Content ──────────────────────────────────────────────────────────────

/** Props for DialogContent */
export type DialogContentProps = React.ComponentPropsWithoutRef<typeof RadixDialog.Content>;

/**
 * Locks the document scroll while mounted.
 *
 * IMPORTANT: render this INSIDE RadixDialog.Content's children, NOT outside it.
 * Radix's Presence gate wraps RadixDialog.Content — children only mount when the
 * dialog is actually open. Placing this outside (e.g. directly in DialogContent
 * before the Portal) causes useEffect to fire even when Dialog open={false},
 * locking the page scroll on mount.
 *
 * Why custom lock: Radix's react-remove-scroll targets <body>, but this app
 * scrolls on <html> (body has min-height:100dvh + overflow-x:clip).
 */
function ScrollLock() {
  useEffect(() => {
    const html = document.documentElement;
    const body = document.body;
    const prevHtmlOverflow = html.style.overflow;
    const prevBodyOverflow = body.style.overflow;
    html.style.overflow = 'hidden';
    body.style.overflow = 'hidden';
    return () => {
      html.style.overflow = prevHtmlOverflow;
      body.style.overflow = prevBodyOverflow;
    };
  }, []);
  return null;
}

/**
 * The main dialog panel. Includes overlay, scroll lock, and a built-in close
 * button. Aria-labelledby is wired to `DialogTitle` by Radix automatically.
 */
export function DialogContent({ className, children, ...props }: DialogContentProps) {
  const t = useT('common');
  return (
    <DialogPortal>
      <DialogOverlay />
      <RadixDialog.Content
        data-motion-role="panel"
        className={cn(
          'z-modal fixed inset-x-0 top-1/2 mx-auto',
          '-translate-y-1/2',
          'max-h-[90dvh] w-full max-w-md overflow-y-auto',
          'border-border-default bg-surface-default rounded-xl border',
          'shadow-xl',
          'px-6 pt-[calc(var(--spacing-6)+var(--safe-area-top))] pb-6',
          'focus:outline-none',
          'motion-overlay-panel-enter motion-overlay-panel-exit',
          className,
        )}
        {...props}
      >
        <ScrollLock />
        <DialogClose
          aria-label={t('close')}
          className="absolute end-4 top-[calc(var(--spacing-4)+var(--safe-area-top))]"
        />
        {children}
      </RadixDialog.Content>
    </DialogPortal>
  );
}

// ─── Sub-components ────────────────────────────────────────────────────────

/** Props for DialogHeader */
export type DialogHeaderProps = React.HTMLAttributes<HTMLDivElement>;

/** Header section of a dialog - wraps title + description. */
export function DialogHeader({ className, ...props }: DialogHeaderProps) {
  return <div className={cn('mb-4 flex flex-col gap-1.5', className)} {...props} />;
}

/** Props for DialogFooter */
export type DialogFooterProps = React.HTMLAttributes<HTMLDivElement>;

/** Footer section of a dialog - for action buttons. */
export function DialogFooter({ className, ...props }: DialogFooterProps) {
  return <div className={cn('mt-6 flex flex-row-reverse gap-2', className)} {...props} />;
}

/** Props for DialogTitle */
export type DialogTitleProps = React.ComponentPropsWithoutRef<typeof RadixDialog.Title>;

/**
 * Dialog title - required for accessibility (aria-labelledby).
 * Radix wires this automatically to the dialog's aria-labelledby.
 */
export function DialogTitle({ className, ...props }: DialogTitleProps) {
  return (
    <RadixDialog.Title
      className={cn('text-text-primary text-lg font-bold', className)}
      {...props}
    />
  );
}

/** Props for DialogDescription */
export type DialogDescriptionProps = React.ComponentPropsWithoutRef<typeof RadixDialog.Description>;

/** Dialog description - optional, wired to aria-describedby by Radix. */
export function DialogDescription({ className, ...props }: DialogDescriptionProps) {
  return (
    <RadixDialog.Description className={cn('text-text-secondary text-sm', className)} {...props} />
  );
}

/** Props for DialogClose */
export interface DialogCloseProps extends React.ComponentPropsWithoutRef<typeof RadixDialog.Close> {
  children?: ReactNode;
}

/**
 * Close button/element for the dialog.
 * For a standalone ✕ icon button, wrap with an accessible `<button>`.
 */
export function DialogClose({ className, children, ...props }: DialogCloseProps) {
  return (
    <RadixDialog.Close
      className={cn(
        'flex h-8 w-8 items-center justify-center rounded-sm',
        'text-text-muted opacity-70',
        'motion-press-feedback transition-opacity hover:opacity-100',
        'focus-visible:ring-brand-primary-500 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',
        className,
      )}
      {...props}
    >
      {children ?? <CloseIcon />}
    </RadixDialog.Close>
  );
}

function CloseIcon() {
  return <X width={16} height={16} strokeWidth={2} aria-hidden="true" />;
}
