import React, { useState, useEffect, Fragment, useRef, useCallback, useLayoutEffect, forwardRef, useImperativeHandle } from 'react';
import Styled from 'styled-components/native';
import { Animated, BackHandler, Easing } from 'react-native';
import { Util } from '~/Utils/utils';

const BackgroundOpacity = Styled(Animated.View)`
    position: absolute;
    left:0; right:0;
    width: 100%;
    height: 100%;
    background-color:black;
`;
const Container = Styled(Animated.View)`
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
    max-height: 100%;
    border: 0px;
    border-color: #e9e9e9;
    border-bottom-width: 1px;
    background-color: #fff;
`;
const ContainerScroller = Styled.ScrollView`
    left: 0px;
    top: 0px;
    width: 100%;
`;
const ContainerNoneScroller = Styled.View`
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100%;
`;
const AnimationDuration = 300;
export default AnimatedContainer = forwardRef(({children, visible, animation="slideDown", scrollable=false, fullScreen=false, fadeIn=false, onRequestClose=()=>{return false}}, ref) => {

    const getStartPos = useCallback(() => {
        if(animation == "slideDown") {
            return {x:0, y:-Util.getScreenHeight()*1.5};
        } else if(animation == "slideUp") {
            return {x:0, y:Util.getScreenHeight()};
        } else if(animation == "slideLeft") {
            return {x:Util.getScreenWidth(), y:0};
        } else if(animation == "slideRight") {
            return {x:-Util.getScreenWidth(), y:0};
        }
        return {x:0, y:-Util.getScreenHeight()};
    },[]);

    const getBackgroundPos = useCallback(() => {
        return {x:0, y:0};
    },[]);

    const getHidePos = useCallback(() => {
        if(animation == "slideDown") {
            return {x: -Util.getScreenWidth() * 2, y: -Util.getScreenHeight() * 2};
        } else if(animation == "slideUp") {
            return {x: Util.getScreenWidth() * 2, y: Util.getScreenHeight() * 2};
        } else if(animation == "slideLeft") {
            return {x: Util.getScreenWidth() * 2, y: Util.getScreenHeight() * 2};
        } else if(animation == "slideRight") {
            return {x: -Util.getScreenWidth() * 2, y: -Util.getScreenHeight() * 2};
        }
        return {x: -Util.getScreenWidth() * 2, y: -Util.getScreenHeight() * 2};
    },[]);

    const setValueXY = useCallback((target, srcValue) => {
        target.setValue({x:srcValue.x, y:srcValue.y});
    },[]);

    const [animPos] = useState(new Animated.ValueXY(getHidePos()));
    const [backgroundPos] = useState(new Animated.ValueXY(getHidePos()));
    const [fadeValue] = useState(new Animated.Value(0));
    const [fadeInValue] = useState(new Animated.Value(0));
    const backHandler = useRef();

    //console.log('AnimatedContainer render - visible : ', visible, ', animPos : ' + animPos);

    const openAnimation = useCallback((onEnd=()=>{}) => {
        console.log("open - animPos : ", animPos);

        setValueXY(backgroundPos, getBackgroundPos());
        setValueXY(animPos, getStartPos());
        console.log("open start - animPos : ", animPos);

        Animated.timing(animPos, {
            toValue: {x:0, y:0},
            duration: AnimationDuration,
            useNativeDriver: true,
        }).start();

        Animated.timing(fadeValue, {
            toValue: 0.5,
            duration: AnimationDuration,
            useNativeDriver: true,
        }).start();

        Animated.timing(fadeInValue, {
            toValue: 1,
            duration: AnimationDuration,
            useNativeDriver: true,
        }).start(() => {
            onEnd();
        });
    }, [animPos, backgroundPos, fadeValue, fadeInValue]);

    const hideAnimation = useCallback((onEnd=()=>{}) => {
        const toStartPos = getStartPos();
        console.log('toStartPos : ', toStartPos);
        Animated.timing(animPos, {
            toValue: toStartPos,
            duration: AnimationDuration,
            useNativeDriver: true,
        }).start();

        Animated.timing(fadeInValue, {
            toValue: 0,
            duration: AnimationDuration,
            useNativeDriver: true,
        }).start();

        Animated.timing(fadeValue, {
            toValue: 0,
            duration: AnimationDuration,
            useNativeDriver: true,
        }).start(() => {
            setValueXY(backgroundPos, getHidePos());
            setValueXY(animPos, getHidePos());
            onEnd();
        });
    }, [animPos, backgroundPos, fadeValue, fadeInValue]);

    useImperativeHandle(ref, () => ({
        hide: (onEnd=()=>{}) => {
            console.log('animated container start hide animation...');
            hideAnimation(onEnd);
        },
        open: (onEnd=()=>{}) => {
            console.log('animated container start open animation...');
            openAnimation(onEnd);
        }
    }), [hideAnimation, openAnimation]);

    useLayoutEffect(() => {
        console.log('changed visible - visible : ', visible);
        if(visible) openAnimation();
        else hideAnimation();
    }, [visible]);

    useLayoutEffect(() => {
        backHandler.current = BackHandler.addEventListener('hardwareBackPress', () => {
            return onRequestClose();
        });
    }, []);

    useEffect(() => () => {
        backHandler.current.remove();
    }, []);

    return (
        <Fragment>
            <Animated.View style={{ 
                position: "absolute",
                left: 0, top: 0, width: "100%", height: "100%",
                backgroundColor:'black', opacity:fadeValue, 
                transform:[{ translateX:backgroundPos.x }, { translateY: backgroundPos.y }] 
            }} />
            <Container style={{ transform:[{ translateX: animPos.x}, {translateY: animPos.y }], height:fullScreen?'100%':'auto' }}>
                {scrollable ? (
                    <ContainerScroller>{children}</ContainerScroller>
                ) : (
                    <ContainerNoneScroller>{children}</ContainerNoneScroller>
                )}
            </Container>
        </Fragment>
    );
})
