import HncyModal from '@/components/HncyModal';
import { Flex, Space } from 'antd';
import classNames from 'classnames';
import { cloneDeep } from 'lodash';
import React, {
  cloneElement,
  forwardRef,
  Fragment,
  memo,
  useCallback,
  useImperativeHandle,
  useMemo,
  useState,
} from 'react';
import styles from './index.less';
import Registry, { ModalKey } from './registry';
import type {
  GlobalModalConfig,
  GlobalModalServicesModalMethods,
  ModalStackType,
} from './type';

let modalIndex = 1000;

/** 获取弹窗内容 */
const getModalElement = (modalKey: ModalKey) => {
  if (Registry.get(modalKey)) {
    return Registry.get(modalKey);
  } else {
    return undefined;
  }
};

/** @module 全局弹窗服务 */
const GlobalModalServices: React.ForwardRefRenderFunction<
  GlobalModalServicesModalMethods,
  any
> = (_, ref) => {
  const [modalStack, setModalStack] = useState<
    Record<string, ModalStackType[]>
  >({});

  /** 同一维度相同类型弹窗只能存在一个 */
  const popupExistsCheck = (thread: string, modalType: string) => {
    return modalStack[thread]?.some((modal) => modal.modalKey === modalType);
  };

  /** @see GlobalModalServicesModalMethods.push */
  const push = useCallback(
    (modalKey: ModalKey, config?: GlobalModalConfig, thread = 0) => {
      /** 生成弹窗id */
      const modalId = `modal_${modalIndex++}`;

      const curModal = getModalElement(modalKey);

      if (!curModal && !config?.component) {
        throw new Error(
          `错误用法，modal ${modalKey} 未注册,且不存在自定义弹窗内容`,
        );
      }

      const newConfig = { ...(curModal?.defaultConfig ?? {}), ...config };

      const newProps = {
        ...(curModal?.defaultProps ?? {}),
        ...(config?.props ?? {}),
      };

      const threadStr = `thread_${thread}`;
      /* 构造弹窗元数据 */
      const newModalStack = {
        ...newConfig,
        modalId,
        props: newProps,
        modalKey,
        thread: threadStr,
        zIndex: modalIndex,
        component: curModal?.modal ?? config?.component,
      };

      if (popupExistsCheck(threadStr, modalKey)) {
        console.warn(
          '同一维度弹窗已存在，请勿重复创建,如果你需要创建弹窗，请使用go方法，或者新增维度',
        );
        return null;
      }

      setModalStack((pre) => {
        const temp = cloneDeep(pre);
        if (temp[threadStr]) {
          temp[threadStr] = [...pre[threadStr], newModalStack];
        } else {
          temp[threadStr] = [newModalStack];
        }
        return temp;
      });
      return modalId;
    },
    [modalStack],
  );

  /** @see GlobalModalServicesModalMethods.go */
  const go = (modalId: string) => {
    const threadId = findThreadId(modalId);
    const index = modalStack[threadId].findIndex(
      (item) => item.modalId === modalId,
    );
    setModalStack((pre) => {
      const temp = { ...pre };
      temp[threadId] = temp[threadId].filter((_, i) => i <= index);
      return temp;
    });
  };

  const findThreadId = (id: string) => {
    const values = Object.values(modalStack);
    const threadId = values.flat().find((item) => item.modalId === id)?.thread;
    if (threadId) {
      return threadId;
    }
    throw new Error('未找到弹窗所在线程');
  };

  /** @see GlobalModalServicesModalMethods.remove */
  const remove = (id: string) => {
    const threadId = findThreadId(id);

    setModalStack((prev) => {
      const temp = { ...prev };
      if (temp[threadId]) {
        temp[threadId] = temp[threadId].filter((item) => item.modalId !== id);
      }
      return temp;
    });
  };

  /** 关闭当前线程的弹窗 */
  const close = (thread: string) => {
    setModalStack((modalStack) => {
      const newStack = { ...modalStack };
      delete newStack[thread];
      return newStack;
    });
  };

  /** @see GlobalModalServicesModalMethods.setOptionsById */
  const setOptionsById = (id: string, config: any) => {
    const threadId = findThreadId(id);

    if (threadId) {
      setModalStack((prev) => {
        const temp = { ...prev };
        temp[threadId] = temp[threadId]?.map((item) => {
          if (item.modalId === id) {
            return {
              ...item,
              ...config,
            };
          }
          return item;
        });
        return temp;
      });
    } else {
      throw new Error('未找到弹窗');
    }
  };

  /** @see GlobalModalServicesModalMethods.clear */
  const clear = () => {
    setModalStack({});
  };

  /**
   * @description modal返回
   *  */
  const goBack = (thread: string) => {
    const threadStr = `thread_${thread}`;
    setModalStack((prev) => {
      const temp = { ...prev };
      if (temp[thread]) {
        temp[threadStr] = temp[threadStr].slice(0, temp[threadStr].length - 1);
      }
      return temp;
    });
  };

  useImperativeHandle(ref, () => ({
    close,
    setOptionsById,
    push,
    goBack: (thread: number) => goBack(`thread_${thread}`),
    remove,
    go,
    clear,
  }));

  /** 标题渲染 */
  const titleRender = (
    modalOption: ModalStackType,
    curThreadNodes: ModalStackType[],
  ) => {
    const { headerLeft, headerRight } = modalOption;
    return (
      <Flex align="center" justify="space-between" style={{ width: '100%' }}>
        <Space>
          <div className={styles.modalTitle}>
            {curThreadNodes?.length && (
              <>
                {curThreadNodes.map((item, index: number) => (
                  <span
                    key={item.modalId}
                    className={classNames(styles.headerItem, {
                      [styles.headerClick]: index != curThreadNodes.length - 1,
                    })}
                    onClick={
                      index != curThreadNodes.length - 1
                        ? () => go(item.modalId)
                        : undefined
                    }
                  >
                    {item.title}
                    {curThreadNodes.length - 1 !== index && (
                      <span style={{ margin: '0 5px' }}>/</span>
                    )}
                  </span>
                ))}
              </>
            )}
          </div>

          {headerLeft
            ? typeof headerLeft === 'function'
              ? headerLeft()
              : headerLeft
            : undefined}
        </Space>

        {headerRight ? (
          <div style={{ marginRight: 34 }}>
            {typeof headerRight === 'function' ? headerRight() : headerRight}
          </div>
        ) : undefined}
      </Flex>
    );
  };

  /** 当前应该渲染的弹窗 */
  const ModalNodes = useMemo(() => {
    const keys = Object.keys(modalStack);

    return keys.map((item) => {
      const stacks = modalStack[item];
      if (stacks.length === 0) {
        return null;
      }
      const lastModal = stacks.at(-1);

      if (lastModal) {
        const {
          w,
          h,
          thread,
          zIndex,
          component: Component,
          style,
          props,
        } = lastModal;

        const metaProps = {
          ...props,
          meta: lastModal,
          modalDispatch: {
            push,
            clear,
            goBack: () => {
              goBack(lastModal.thread);
            },
            go,
            setOptions: (config: GlobalModalConfig) => {
              setOptionsById(lastModal.modalId, config);
            },
          },
        };

        return (
          <HncyModal
            onCancel={() => close(thread)}
            width={w}
            height={h}
            key={lastModal.modalId}
            style={{ ...style, zIndex: zIndex ?? 1000 }}
            open
            titleRender={titleRender.bind(this, lastModal, stacks)}
          >
            {
              /** 传入元素实例的情况 */
              React.isValidElement(Component) ? (
                cloneElement(Component as React.ReactElement<any>, {
                  ...metaProps,
                })
              ) : (
                //@ts-ignore
                <Component {...metaProps} />
              )
            }
          </HncyModal>
        );
      }
      return <div></div>;
    });
  }, [modalStack]);

  return <Fragment>{ModalNodes}</Fragment>;
};

export default memo(forwardRef(GlobalModalServices));
