import React, { useRef, useImperativeHandle, useState, useEffect, useContext } from 'react';
import { Arrow, PopupContainer } from './style';
import { useSpring } from 'react-spring';
import { getSiblingLocation } from './helper';
import { IPlacement } from './types';
import { useClickOutSide } from '../../utils/hooks';

function mapTransformOrigin(placement: IPlacement) {
    switch (placement) {
        case 'topLeft':
            return '16px 100%';
        case 'top':
            return 'calc(50% - 4px) 100%';
        case 'topRight':
            return 'calc(100% - 16px) 100%';
        case 'rightTop':
            return '-4px 12px';
        case 'right':
            return '-4px calc(50% - 4px)';
        case 'rightBottom':
            return '-4px calc(100% - 16px)';
        case 'bottomLeft':
            return '16px 0';
        case 'bottom':
            return 'calc(50% - 4px) 0';
        case 'bottomRight':
            return 'calc(100% - 16px) 0';
        case 'leftTop':
            return '100% 16px';
        case 'left':
            return '100% calc(50% - 4px)';
        case 'leftBottom':
            return '100% calc(100% - 16px)';
    }
}
export function setPopupLocation(placement: IPlacement, target: DOMRect, popup: HTMLElement): any {
    switch (placement) {
        case 'topLeft':
            return {
                left: target.left,
                top: target.top - popup.offsetHeight - 10,
            };
        case 'top':
            return {
                left: target.left + target.width / 2 - popup.offsetWidth / 2,
                top: target.top - popup.offsetHeight - 10,
            };
        case 'topRight':
            return {
                right: target.right,
                top: target.top - popup.offsetHeight - 10,
            };
        case 'rightTop':
            return {
                left: target.left + target.width + 10,
                top: target.top,
            };
        case 'right':
            return {
                left: target.left + target.width + 10,
                top: target.top + target.height / 2 - popup.offsetHeight / 2,
            };
        case 'rightBottom':
            return {
                left: target.left + target.width + 10,
                bottom: target.bottom,
            };
        case 'bottomLeft':
            return {
                left: target.left,
                bottom: target.bottom - popup.offsetHeight - 10,
            };
        case 'bottom':
            return {
                left: target.left + target.width / 2 - popup.offsetWidth / 2,
                bottom: target.bottom - popup.offsetHeight - 10,
            };
        case 'bottomRight':
            return {
                right: target.right,
                bottom: target.bottom - popup.offsetHeight - 10,
            };
        case 'leftTop':
            return {
                left: target.left - popup.offsetWidth - 10,
                top: target.top,
            };
        case 'left':
            return {
                left: target.left - popup.offsetWidth - 10,
                top: target.top + target.height / 2 - popup.offsetHeight / 2,
            };
        case 'leftBottom':
            return {
                left: target.left - popup.offsetWidth - 10,
                bottom: target.bottom,
            };
    }
}

export type IProps = {
    trigger: 'click' | 'hover';
    content: React.ReactNode;
    themeColor: 'white' | 'black';
    visible?: boolean;
    onVisibleChange?: (visible: boolean) => void;
    siblingRef: any;
    placement: IPlacement;
    className?: string;
    style?: React.CSSProperties;
};
const Popup = function(props: IProps, ref: any) {
    const { themeColor, content, trigger, siblingRef, onVisibleChange, placement, visible, ...rest } = props;
    const controlledVisible = 'visible' in props;

    const wrapRef: any = useRef();
    const [show, setShow] = useState(controlledVisible ? props.visible : false);
    const style = useSpring({
        opacity: show ? 1 : 0,
        transform: `scale(${show ? 1 : 0})`,
        transformOrigin: mapTransformOrigin(placement),
        config: { mass: 5, friction: 180, tension: 3000, clamp: true },
    });

    useEffect(() => {
        if (controlledVisible) {
            var id = setTimeout(() => {
                const loc = getSiblingLocation(siblingRef);
                //setPos({
                //    left: loc.left,
                //    top: loc.top - wrapRef.current.offsetHeight - 10,
                //});
                setPos(setPopupLocation(placement, loc as DOMRect, wrapRef.current as HTMLElement));
                setShow(props.visible);
            }, 100);
        }
        return () => clearTimeout(id);
    }, [controlledVisible, props.visible, siblingRef.current]);
    const [cursorIn, setCursor] = useState(false);

    useClickOutSide(
        siblingRef,
        e => {
            if (trigger === 'click' && !wrapRef.current.contains(e)) {
                if (!controlledVisible) {
                    setShow(false);
                } else {
                    onVisibleChange && show && onVisibleChange(false);
                }
            }
        },
        true
    );

    const [pos, setPos] = useState({ left: 0, top: 0 });
    useImperativeHandle(ref, () => ({
        dom: wrapRef.current,
        setVisible: setShow,
        visible: show,
        cursorIn,
        setPos,
    }));
    return (
        <PopupContainer
            placement={placement}
            onMouseEnter={() => {
                if (trigger === 'hover') {
                    setCursor(true);
                }
            }}
            onMouseLeave={() => {
                if (trigger === 'hover') {
                    setCursor(false);
                    if (!controlledVisible) {
                        setShow(false);
                    } else {
                        onVisibleChange && onVisibleChange(false);
                    }
                }
            }}
            data-contrast={themeColor === 'black'}
            ref={wrapRef}
            style={{ ...pos, ...style }}
            {...rest}
        >
            {content}
            <Arrow contrast={themeColor === 'black'} placement={placement} />
        </PopupContainer>
    );
};
export default React.forwardRef(Popup);
