import * as React from "react";
import { Animated, Platform, StyleSheet, View } from "react-native";

const getOutputRange = (width, isReversed) => isReversed ? [width, -width] : [-width, width];

type Props = {
    width?: number,
    height?: number,
    delay?: number,
    duration?: number,
    isInteraction?: boolean,
};

type State = {
    beginShimmerPosition?: Animated.Value,
};

const defaultProps = {
    delay: 0,
    duration: 1000,
    isInteraction: true
};

class ShimmerPlaceholder extends React.PureComponent<Props, State> {

    static defaultProps = defaultProps;

    state = {
        beginShimmerPosition: new Animated.Value(-1)
    }

    getAnimated = () => {
        const { delay, duration, isInteraction } = this.props;
        return Animated.loop(Animated.timing(this.state.beginShimmerPosition, {
            toValue: 1,
            delay,
            duration,
            useNativeDriver: !["web"].includes(Platform.OS),
            isInteraction
        }));
    }
    animatedValue = this.getAnimated()

    render() {
        return (
            <BasedShimmerPlaceholder
                {...this.props}
                animatedValue={this.animatedValue}
                beginShimmerPosition={this.state.beginShimmerPosition}
            />
        );
    }
}

const BasedShimmerPlaceholder = (props) => {
    const {
        width = 200,
        height = 15,
        // duration = 1000,
        // delay = 0,
        shimmerColors = ["#ebebeb", "#c5c5c5", "#ebebeb"],
        isReversed = false,
        stopAutoRun = false,
        visible,
        location = [0.3, 0.5, 0.7],
        style,
        contentStyle,
        shimmerStyle,
        // isInteraction = true,
        LinearGradient = View,
        // LinearGradient = global.Expo ? global.Expo.LinearGradient : View,
        children,
        animatedValue,
        beginShimmerPosition,
        shimmerWidthPercent = 1,
    } = props;

    const linearTranslate = beginShimmerPosition.interpolate({
        inputRange: [-1, 1],
        outputRange: getOutputRange(width, isReversed)
    });

    React.useEffect(() => {
        if (!stopAutoRun) {
            animatedValue.start();
        }
        return () => {
            animatedValue.stop();
        };
    }, [stopAutoRun]);

    React.useEffect(() => {
        if (visible) {
            animatedValue.stop();
        }
        if (!visible && !stopAutoRun) {
            animatedValue.start();
        }
    }, [visible, stopAutoRun]);

    return (
        <View
            style={[!visible && { height, width }, styles.container, !visible && shimmerStyle, style]}
        >
            {/* Force render children to restrict rendering twice */}
            <View style={[!visible && { width: 0, height: 0, opacity: 0 }, visible && contentStyle]}>{children}</View>
            {
                !visible && (
                    <View style={{ flex: 1, backgroundColor: shimmerColors[0] }}>
                        <Animated.View
                            style={{ flex: 1, transform: [{ translateX: linearTranslate }] }}
                        >
                            <LinearGradient
                                colors={shimmerColors}
                                style={{ flex: 1, width: width * shimmerWidthPercent }}
                                start={{
                                    x: -1,
                                    y: 0.5
                                }}
                                end={{
                                    x: 2,
                                    y: 0.5
                                }}
                                locations={location}
                            />
                        </Animated.View>

                    </View>
                )
            }
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        overflow: "hidden"
    },
});

/**
 * To create ShimmerPlaceholder by Linear Gradient. Only useful when you use 3rd party,
 * For example: react-native-linear-gradient
 * @param {Linear Gradient Component} LinearGradient - 'expo-linear-gradient' by default
 *
 * @example
 *
 * import LinearGradient from 'react-native-linear-gradient';
 * import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder'
 *
 * const ShimmerPlaceHolder = createShimmerPlaceholder(LinearGradient)
 *
 * ...
 *
 * <ShimmerPlaceHolder />
 */
export const createShimmerPlaceholder = (LinearGradient = View) => React.forwardRef<ShimmerPlaceholder, Props>((props, ref) =>
    // @ts-ignore
    <ShimmerPlaceholder LinearGradient={LinearGradient} ref={ref} {...props} />);

export default ShimmerPlaceholder;
