/*
 * @Author: 赵伟
 * @Date: 2024-04-13 10:08:35
 * @Description: 以函数的方式打开 Modal
 */
import { ConfigProvider, type ModalProps } from 'antd';
import { globalConfig } from 'antd/es/config-provider';
import zhCN from 'antd/locale/zh_CN';
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';

const destroyFns: (() => void)[] = [];

/**
 * Function to open an Ant Design modal.
 *
 * @param modal - The function that renders the modal content.
 * @param modalProps - The modal properties.
 * @return An object with a destroy method to close the modal.
 */
export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
  modal: (props: T) => React.ReactNode,
  modalProps: T,
) => {
  const CustomModel = modal;
  const container = document.createDocumentFragment();
  const root = createRoot(container);
  const { afterClose, onCancel } = modalProps;
  const global = globalConfig();
  let timeoutId: ReturnType<typeof setTimeout>;

  function destroy() {
    const index = destroyFns.indexOf(close);
    if (index !== -1) {
      destroyFns.splice(index, 1);
    }

    root.unmount();
  }

  function handleAfterClose() {
    afterClose?.();
    // Warning: Attempted to synchronously unmount a root while React was already rendering.
    // React cannot finish unmounting the root until the current render has completed, which may lead to a race condition.
    setTimeout(() => {
      destroy();
    }, 0);
  }

  function handleCancel(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
    if (onCancel) {
      onCancel(e);
    } else {
      close();
    }
  }

  function render(props: T) {
    clearTimeout(timeoutId);

    timeoutId = setTimeout(() => {
      const rootPrefixCls = global.getPrefixCls();
      const iconPrefixCls = global.getIconPrefixCls();
      const theme = global.getTheme();
      const dom = (
        <CustomModel {...props} onCancel={handleCancel} afterClose={handleAfterClose}></CustomModel>
      );

      root.render(
        <ConfigProvider
          prefixCls={rootPrefixCls}
          iconPrefixCls={iconPrefixCls}
          theme={theme}
          locale={zhCN}
        >
          {global.holderRender ? global.holderRender(dom) : dom}
        </ConfigProvider>,
      );
    });
  }

  function close() {
    render({ ...modalProps, open: false });
  }

  render({ ...modalProps, open: true });

  destroyFns.push(close);

  return {
    close,
  };
};

/**
 * Generates a custom hook for managing an Ant Design modal.
 *
 * @param modal - The function that renders the modal content.
 * @param defaultProps - The default modal properties.
 * @return The modal component, open function, and close function.
 */

export const useModal = <T extends ModalProps>(
  modal: (props: T) => React.ReactNode,
  defaultProps?: T,
) => {
  const [visible, setVisible] = useState(false);
  const [props, setProps] = useState<T>(defaultProps || ({} as T));
  const CustomModel = modal;

  const open = (props: T) => {
    setProps((prev) => ({
      ...prev,
      ...props,
    }));
    setVisible(true);
  };

  const close = () => {
    setVisible(false);
  };

  return [<CustomModel key="modal" open={visible} {...props} />, open, close] as const;
};

// 关闭没有手动关闭的 Modal
export const closeAllModals = () => {
  let close = destroyFns.pop();
  while (close) {
    close();
    close = destroyFns.pop();
  }
};
