import PropTypes from 'prop-types';
import { Close as CloseIcon } from '@mui/icons-material';
import {
  Typography,
  Dialog as MuiDialog,
  DialogContent as MuiDialogContent,
  DialogActions,
  IconButton,
  useMediaQuery,
  Box,
} from '@mui/material';

import { styled, useTheme } from '../Theme';

/**
 * @typedef {import('@mui/material').DialogProps} MuiDialogProps
 * @typedef {import('@mui/material').PaperProps & {
 *   minWidth?: number | string,
 *   minHeight?: number | string,
 * }} PaperStyle
 */

/**
  @typedef  {Object} UxDialogProps
  @property {React.ReactNode} children - The content of the dialog.
  @property {React.ReactNode} [title] - The title of the dialog.
  @property {React.ReactNode} [prepend] - Content to be displayed before the dialog title.
  @property {React.ReactNode} [toolbar] - Content to be displayed in the top toolbar of the dialog.
  @property {React.ReactNode} [actions] - Content to be displayed in the bottom actions toolbar of the dialog.
  @property {boolean} [showCloseButton=true] - Whether or not to show the close button.
  @property {'left'|'center'|'right'} [actionsPosition='right'] - The position of the actions toolbar.
  @property {PaperStyle} [PaperProps] - Props to be passed down to the dialog paper.
  @property {{content: object, content: object}} [slotProps]
  @property {(event: React.SyntheticEvent, reason: string) => void} [onClose] - Callback function fired when the dialog is closed.
*/

/**
 * @typedef {Omit<MuiDialogProps, 'title' | 'children' | 'onClose' | 'PaperProps' | 'slotProps'> & UxDialogProps} DialogProps
 */

/**
 * Dialog
 *
 * - 固定尺寸或特殊的尺寸控制需求, 可使用 PaperProps.style (不再提供 width/height 等 props)
 *   注意: 当设置明确的 width 时, 可能需要同时设置 maxWidth=false (mui dialog 默认 maxWidth=sm, 设置的 width 可能受限)
 * - 添加默认最小尺寸 (300x300), 在需要 先展示 loading 再展示异步数据 的时候避免 loading 阶段窗口过小
 */
/**
 * @description
 * @param {DialogProps} props
 * @return {React.ReactComponentElement<any, DialogProps>}
 */
function Dialog({
  children,
  title = '',
  prepend = null,
  toolbar = null,
  actions = null,
  showCloseButton = true,
  actionsPosition = 'right',
  PaperProps = {},
  slotProps = {},
  ...rest
}) {
  const theme = useTheme();
  // 不管是否是 mobile 设备, 只要屏宽 < sm, dialog 就处于 mobile 模式
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
  const showHeader = title || showCloseButton || toolbar;
  const handleOnClose = (e, reason) => {
    // escapeKeyDown/backdropClick
    const { onClose } = rest;
    if (onClose) {
      onClose(e, reason);
    }
  };
  // 添加默认最小尺寸 (300x300)
  PaperProps.style = Object.assign(
    {
      minWidth: 300,
      minHeight: 300,
    },
    PaperProps.style
  );

  const closeButton = (
    <IconButton className="ux-dialog_closeButton" onClick={(e) => handleOnClose(e, 'closeButton')}>
      <CloseIcon />
    </IconButton>
  );

  return (
    <StyledMuiDialog fullScreen={isMobile} onClose={handleOnClose} PaperProps={PaperProps} {...rest}>
      {showHeader && (
        <Header {...slotProps.header} className="ux-dialog_header" isMobile={isMobile}>
          <div className="ux-dialog_left">
            {showCloseButton && isMobile && closeButton}
            {prepend && <div className="ux-dialog_prepend">{prepend}</div>}
            {title && (
              <Typography variant="h6" className="ux-dialog_title">
                {title}
              </Typography>
            )}
          </div>

          <div className="ux-dialog_right">
            <div className="ux-dialog_toolbar">{toolbar}</div>
            {showCloseButton && !isMobile && closeButton}
          </div>
        </Header>
      )}
      <MuiDialogContent {...slotProps.content}>{children}</MuiDialogContent>
      {actions && <DialogActions className={`ux-dialog_actions--${actionsPosition}`}>{actions}</DialogActions>}
    </StyledMuiDialog>
  );
}

Dialog.propTypes = {
  children: PropTypes.node.isRequired,
  title: PropTypes.node,
  // 在 title 之前追加内容, 比如返回按钮
  prepend: PropTypes.node,
  // 顶部工具栏, 在 close button 另一侧
  toolbar: PropTypes.node,
  actions: PropTypes.node,
  showCloseButton: PropTypes.bool,
  actionsPosition: PropTypes.oneOf(['left', 'center', 'right']),
  PaperProps: PropTypes.object,
  slotProps: PropTypes.shape({
    content: PropTypes.object,
    header: PropTypes.object,
  }),
  onClose: PropTypes.func,
};

/**
 * @type {import('@emotion/styled').StyledComponent<import('@mui/material').DialogProps, {}, { ref?: React.Ref<any> | undefined;}>}
 */
const StyledMuiDialog = styled(MuiDialog)`
  .MuiDialog-paper {
    ${(props) => (props.fullScreen ? 'border-radius: 0;' : '')};
  }
  .MuiDialogContent-root {
    padding: 16px 24px;
  }
  .MuiDialogActions-root {
    padding: 8px 24px 16px 24px;
  }
  .MuiDialogActions-root.ux-dialog_actions--left {
    justify-content: flex-start;
  }
  .MuiDialogActions-root.ux-dialog_actions--right {
    justify-content: flex-end;
  }
  .MuiDialogActions-root.ux-dialog_actions--center {
    justify-content: center;
  }
`;

/** @type {import('@emotion/styled').StyledComponent<import('react').ComponentPropsWithoutRef<"div">, {}, { ref?: React.Ref<any> | undefined;}>} */
const Header = styled(Box, { shouldForwardProp: (prop) => prop !== 'isMobile' })`
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
  .ux-dialog_left {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    min-width: 0;
  }
  .ux-dialog_right {
    display: flex;
    justify-content: flex-end;
    align-items: center;
  }
  .ux-dialog_toolbar {
    display: flex;
    align-items: center;
  }
  .ux-dialog_title {
    margin: 0;
    font-size: 18px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ux-dialog_closeButton {
    /* 使 closeButton 与 content 左/右对齐 */
    ${(props) => (props.isMobile ? 'margin-left: -12px;' : 'margin-right: -12px;')}
    transition: transform 0.3s;
    transform: rotate(0deg);
    &:hover {
      transform: rotate(90deg);
    }
  }
`;

export default Dialog;
