import { MouseEvent } from 'react';
import { action, observable } from 'mobx';
import { ModalProps } from 'choerodon-ui/pro/lib/modal/Modal';
import { ConfigContextValue } from 'choerodon-ui/lib/config-provider/ConfigContext';
import { EventManager } from 'choerodon-ui/dataset';
import { getMousePosition, transformZoomData } from '../util';

export type MousePosition = { x: number; y: number; vw: number; vh: number };

export interface ModalContainerState {
  modals: ModalProps[];
  mount?: HTMLElement;
}

export type DrawerOffsets = { 'slide-up': number[]; 'slide-right': number[]; 'slide-down': number[]; 'slide-left': number[] };

export interface IModalContainer {
  context: ConfigContextValue;

  maskHidden: boolean;

  active: boolean;

  drawerOffsets: DrawerOffsets;

  clear(closeByLocationChange?: boolean);

  getContainer(): HTMLElement | undefined;

  getOffsetContainer(): HTMLElement | null;

  mergeModals(modals: ModalProps[]);

  state: ModalContainerState;

  open(props: ModalProps);

  close(props: ModalProps);

  update(props: ModalProps);

  isUnMount: boolean;
}

export type ModalManagerType = {
  containerInstances: IModalContainer[];
  addInstance: (instance: IModalContainer) => void;
  removeInstance: (instance: IModalContainer) => void;
  getKey: () => string;
  clear: (closeByLocationChange?: boolean) => void;
  registerMousePosition: () => void;
  mousePositionEventBound: WeakSet<Document>;
  mousePosition?: MousePosition;
  containerStyles: WeakMap<HTMLElement, { overflow: string, paddingRight: string, position: string }>
  root?: HTMLElement;
}

const KeyGen = (function* (id) {
  while (true) {
    yield `modal-${id}`;
    id += 1;
  }
})(1);

const containerInstances: IModalContainer[] = observable.array<IModalContainer>();

const removeInstance: (instance: IModalContainer) => void = action((instance: IModalContainer) => {
  const index = containerInstances.indexOf(instance);
  if (index > -1) {
    containerInstances.splice(index, 1);
  }
});

const addInstance: (instance: IModalContainer) => void = action((instance: IModalContainer) => {
  if (instance.isUnMount) {
    return;
  }
  removeInstance(instance);
  containerInstances.unshift(instance);
});

function getKey(): string {
  return KeyGen.next().value;
}

function clear(closeByLocationChange) {
  containerInstances.forEach((instance) => {
    instance.clear(closeByLocationChange);
  });
}

const mousePositionEventBound = new WeakSet<Document>();

function registerMousePosition() {
  const doc = typeof window === 'undefined' ? undefined : document;
  if (doc && !mousePositionEventBound.has(doc)) {
    // 只有点击事件支持从鼠标位置动画展开
    new EventManager(doc).addEventListener(
      'click',
      (e: MouseEvent) => {
        ModalManager.mousePosition = getMousePosition(transformZoomData(e.clientX), transformZoomData(e.clientY), window);
        // 100ms 内发生过点击事件,则从点击位置动画展示
        // 否则直接 zoom 展示
        // 这样可以兼容非点击方式展开
        setTimeout(() => (delete ModalManager.mousePosition), 100);
      },
      true,
    );
    mousePositionEventBound.add(doc);
  }
}

const ModalManager: ModalManagerType = {
  addInstance,
  removeInstance,
  getKey,
  mousePositionEventBound,
  containerInstances,
  clear,
  containerStyles: new WeakMap(),
  registerMousePosition,
};

export default ModalManager;