//
// Copyright 2023 DXOS.org
//

import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
import { createContext } from '@radix-ui/react-context';
import React, { type ForwardRefExoticComponent, type FunctionComponent, forwardRef } from 'react';

import { useThemeContext } from '../../hooks';
import { ElevationProvider } from '../../primitives';
import { type DialogSize } from '../../theme';
import { type ThemedClassName } from '../../util';
import { Column } from '../Column';
import {
  Dialog,
  type DialogActionBarProps,
  type DialogActionIconButtonProps,
  type DialogBodyProps,
  type DialogHeaderProps,
} from './Dialog';

//
// Root
//

type AlertDialogRootProps = AlertDialogPrimitive.AlertDialogProps;

const AlertDialogRoot: FunctionComponent<AlertDialogRootProps> = (props) => (
  <ElevationProvider elevation='dialog'>
    <AlertDialogPrimitive.Root {...props} />
  </ElevationProvider>
);

//
// Trigger
//

type AlertDialogTriggerProps = AlertDialogPrimitive.AlertDialogTriggerProps;

const AlertDialogTrigger = AlertDialogPrimitive.Trigger;

//
// Portal
//

type AlertDialogPortalProps = AlertDialogPrimitive.AlertDialogPortalProps;

const AlertDialogPortal = AlertDialogPrimitive.Portal;

//
// Cancel
//

type AlertDialogCancelProps = AlertDialogPrimitive.AlertDialogCancelProps;

const AlertDialogCancel = AlertDialogPrimitive.Cancel;

//
// Action
//

type AlertDialogActionProps = AlertDialogPrimitive.AlertDialogActionProps;

const AlertDialogAction = AlertDialogPrimitive.Action;

//
// Context
//

type OverlayLayoutContextValue = { inOverlayLayout?: boolean };

const ALERT_DIALOG_OVERLAY_NAME = 'AlertDialog.Overlay';
const ALERT_DIALOG_CONTENT_NAME = 'AlertDialog.Content';

const [OverlayLayoutProvider, useOverlayLayoutContext] = createContext<OverlayLayoutContextValue>(
  ALERT_DIALOG_OVERLAY_NAME,
  { inOverlayLayout: false },
);

//
// Overlay
//

type AlertDialogOverlayProps = ThemedClassName<
  AlertDialogPrimitive.AlertDialogOverlayProps & { blockAlign?: 'center' | 'start' | 'end' }
>;

const AlertDialogOverlay: ForwardRefExoticComponent<AlertDialogOverlayProps> = forwardRef<
  HTMLDivElement,
  AlertDialogOverlayProps
>(({ classNames, children, blockAlign, ...props }, forwardedRef) => {
  const { tx } = useThemeContext();
  return (
    <AlertDialogPrimitive.Overlay
      {...props}
      data-block-align={blockAlign}
      className={tx('dialog.overlay', {}, classNames)}
      ref={forwardedRef}
    >
      <OverlayLayoutProvider inOverlayLayout>{children}</OverlayLayoutProvider>
    </AlertDialogPrimitive.Overlay>
  );
});

AlertDialogOverlay.displayName = ALERT_DIALOG_OVERLAY_NAME;

//
// Content
//

type AlertDialogContentProps = ThemedClassName<AlertDialogPrimitive.AlertDialogContentProps> & { size?: DialogSize };

const AlertDialogContent: ForwardRefExoticComponent<AlertDialogContentProps> = forwardRef<
  HTMLDivElement,
  AlertDialogContentProps
>(({ classNames, children, size = 'md', ...props }, forwardedRef) => {
  const { tx } = useThemeContext();
  const { inOverlayLayout } = useOverlayLayoutContext(ALERT_DIALOG_CONTENT_NAME);
  return (
    <AlertDialogPrimitive.Content
      {...props}
      className={tx('dialog.content', { inOverlayLayout, size }, classNames)}
      ref={forwardedRef}
    >
      <Column.Root classNames='dx-expander' gutter='lg'>
        {children}
      </Column.Root>
    </AlertDialogPrimitive.Content>
  );
});

AlertDialogContent.displayName = ALERT_DIALOG_CONTENT_NAME;

//
// Title
//

type AlertDialogTitleProps = ThemedClassName<AlertDialogPrimitive.AlertDialogTitleProps> & { srOnly?: boolean };

const AlertDialogTitle: ForwardRefExoticComponent<AlertDialogTitleProps> = forwardRef<
  HTMLHeadingElement,
  AlertDialogTitleProps
>(({ classNames, srOnly, ...props }, forwardedRef) => {
  const { tx } = useThemeContext();
  return (
    <AlertDialogPrimitive.Title {...props} className={tx('dialog.title', { srOnly }, classNames)} ref={forwardedRef} />
  );
});

//
// Description
//

type AlertDialogDescriptionProps = ThemedClassName<AlertDialogPrimitive.AlertDialogDescriptionProps> & {
  srOnly?: boolean;
};

const AlertDialogDescription: ForwardRefExoticComponent<AlertDialogDescriptionProps> = forwardRef<
  HTMLParagraphElement,
  AlertDialogDescriptionProps
>(({ classNames, srOnly, ...props }, forwardedRef) => {
  const { tx } = useThemeContext();
  return (
    <AlertDialogPrimitive.Description
      {...props}
      className={tx('dialog.description', { srOnly }, classNames)}
      ref={forwardedRef}
    />
  );
});

//
// AlertDialog
//

export const AlertDialog = {
  Root: AlertDialogRoot,
  Trigger: AlertDialogTrigger,
  Portal: AlertDialogPortal,
  Overlay: AlertDialogOverlay,
  Content: AlertDialogContent,
  // Shared with Dialog.
  Header: Dialog.Header,
  Body: Dialog.Body,
  Title: AlertDialogTitle,
  Description: AlertDialogDescription,
  ActionBar: Dialog.ActionBar,
  ActionIconButton: Dialog.ActionIconButton,
  // AlertDialog-specific dismissal.
  Cancel: AlertDialogCancel,
  Action: AlertDialogAction,
};

export type {
  DialogActionBarProps as AlertDialogActionBarProps,
  DialogActionIconButtonProps as AlertDialogActionIconButtonProps,
  AlertDialogActionProps,
  DialogBodyProps as AlertDialogBodyProps,
  AlertDialogCancelProps,
  AlertDialogContentProps,
  AlertDialogDescriptionProps,
  // Re-export shared types.
  DialogHeaderProps as AlertDialogHeaderProps,
  AlertDialogOverlayProps,
  AlertDialogPortalProps,
  AlertDialogRootProps,
  AlertDialogTitleProps,
  AlertDialogTriggerProps,
};
