import React, { useEffect, useRef } from 'react';
import { ChildrenSibling } from './style';
import { getSiblingLocation, mountContainer } from './helper';
import { genUUID } from 'utils';
import { setPopupLocation } from './popup';
import { IPopover } from './types';

const ref: any = React.createRef();

mountContainer(ref);

const Popover = function(props: IPopover) {
    const { children, trigger, onVisibleChange, placement, delay = 0, ...rest } = props;
    const controlledVisible = 'visible' in props;
    // function component 不太好获得children的ref，只能添加一个隐藏sibling 获取children的dom引用
    // https://github.com/facebook/react/issues/4244
    const siblingRef: any = useRef();
    const uid: any = useRef();
    const openTimeoutId = useRef<number>();
    useEffect(() => {
        uid.current = genUUID();
    }, []);

    // insert popup dom
    useEffect(() => {
        if (!ref) {
            return;
        }
        ref.current.setPopups((p: any) => {
            const find = p.findIndex((s: any) => s.uid === uid.current);
            if (~find) {
                // modify absolute position in case dom layout change
                const loc = getSiblingLocation(siblingRef);
                setTimeout(() => {
                    //p[find].ref.current.setPos({
                    //    left: loc.left,
                    //    top: loc.top - p[find].ref.current.dom.offsetHeight - 10,
                    //});
                    p[find].ref.current.setPos(setPopupLocation(placement, loc as DOMRect, p[find].ref.current.dom));
                }, 0);
                p[find] = {
                    ...p[find],
                    trigger,
                    ...rest,
                };
            } else {
                p.push({
                    uid: uid.current,
                    trigger,
                    ref: React.createRef(),
                    siblingRef,
                    onVisibleChange,
                    placement,
                    ...rest,
                });
            }
            return [...p];
        });
    }, [trigger, rest.content, rest.themeColor, rest.visible, placement]);

    useEffect(() => {
        var node: any, openHandle: any, closeHandle: any, toggleHandle: any, popupRef: any;
        setTimeout(() => {
            node = siblingRef.current && siblingRef.current.previousElementSibling;
            if (!ref || !node) {
                return;
            }
            const find = ref.current.popups.find((p: any) => p.uid === uid.current);
            if (!find) {
                return;
            }
            popupRef = find.ref;
            openHandle = () => {
                const loc = getSiblingLocation(siblingRef);

                //popupRef.current.setPos({ left: loc.left, top: loc.top - popupRef.current.dom.offsetHeight - 10 });
                if (openTimeoutId.current) {
                    clearTimeout(openTimeoutId.current);
                }
                openTimeoutId.current = setTimeout(() => {
                    popupRef.current.setPos(setPopupLocation(placement, loc as DOMRect, popupRef.current.dom));
                    if (!controlledVisible) {
                        popupRef.current.setVisible(true);
                    } else {
                        onVisibleChange && onVisibleChange(true);
                    }
                }, delay);
            };
            closeHandle = (e: any) => {
                clearTimeout(openTimeoutId.current);
                setTimeout(() => {
                    if (!popupRef.current.cursorIn) {
                        if (!controlledVisible) {
                            popupRef.current.setVisible(false);
                        } else {
                            onVisibleChange && onVisibleChange(false);
                        }
                    }
                }, 150);
            };
            toggleHandle = () => {
                const loc = getSiblingLocation(siblingRef);
                //popupRef.current.setPos({ left: loc.left, top: loc.top - popupRef.current.dom.offsetHeight - 10 });
                popupRef.current.setPos(setPopupLocation(placement, loc as DOMRect, popupRef.current.dom));

                if (!controlledVisible) {
                    popupRef.current.setVisible((s: boolean) => !s);
                } else {
                    onVisibleChange && onVisibleChange(!popupRef.current.visible);
                }
            };
            if (trigger === 'hover') {
                node.addEventListener('mouseenter', openHandle);
                node.addEventListener('mouseleave', closeHandle);
            } else {
                node.addEventListener('mousedown', toggleHandle);
            }
        }, 0);

        return () => {
            if (popupRef && popupRef.current) {
                popupRef.current.setVisible(false);
            }
            if (trigger === 'hover') {
                node && node.removeEventListener('mouseenter', openHandle);
                node && node.removeEventListener('mouseleave', closeHandle);
            } else {
                node && node.removeEventListener('mousedown', toggleHandle);
            }
        };
    }, [trigger, controlledVisible, placement]);

    return (
        <>
            {children}
            <ChildrenSibling ref={siblingRef} />
        </>
    );
};
Popover.defaultProps = {
    themeColor: 'white',
    trigger: 'hover',
    placement: 'topLeft',
    delay: 0,
};

export default Popover;
