import { Animated, Easing, View, Platform } from "react-native";
import { BaseItemAnimator } from "../../../../core/ItemAnimator";

interface UnmountAwareView extends View {
    _isUnmountedForRecyclerListView?: boolean;
    _lastAnimVal?: Animated.ValueXY | null;
}

const IS_WEB = Platform.OS === "web";

/**
 * Default implementation of RLV layout animations for react native. These ones are purely JS driven. Also, check out DefaultNativeItemAnimator
 * for an implementation on top of LayoutAnimation. We didn't use it by default due the fact that LayoutAnimation is quite
 * unstable on Android and to avoid unnecessary interference with developer flow. It would be very easy to do so manually if
 * you need to. Check DefaultNativeItemAnimator for inspiration. LayoutAnimation definitely gives better performance but is
 * hardly customizable.
 */
export class DefaultJSItemAnimator implements BaseItemAnimator {
    public shouldAnimateOnce: boolean = true;
    private _hasAnimatedOnce: boolean = false;
    private _isTimerOn: boolean = false;
    public animateWillMount(atX: number, atY: number, itemIndex: number): void {
        //no need
    }
    public animateDidMount(atX: number, atY: number, itemRef: object, itemIndex: number): void {
        //no need
    }

    public animateWillUpdate(fromX: number, fromY: number, toX: number, toY: number, itemRef: object, itemIndex: number): void {
        this._hasAnimatedOnce = true;
    }

    public animateShift(fromX: number, fromY: number, toX: number, toY: number, itemRef: object, itemIndex: number): boolean {
        if (fromX !== toX || fromY !== toY) {
            if (!this.shouldAnimateOnce || this.shouldAnimateOnce && !this._hasAnimatedOnce) {
                const viewRef = itemRef as UnmountAwareView,
                 animXY = new Animated.ValueXY({ x: fromX, y: fromY });

                animXY.addListener((value) => {
                    if (viewRef._isUnmountedForRecyclerListView) {
                        animXY.stopAnimation();
                        return;
                    }
                    viewRef.setNativeProps(this._getNativePropObject(value.x, value.y));
                });
                if (viewRef._lastAnimVal) {
                    viewRef._lastAnimVal.stopAnimation();
                }
                viewRef._lastAnimVal = animXY;
                Animated.timing(animXY, {
                    toValue: { x: toX, y: toY },
                    duration: 200,
                    easing: Easing.out(Easing.ease),
                    useNativeDriver: BaseItemAnimator.USE_NATIVE_DRIVER,
                }).start(() => {
                    viewRef._lastAnimVal = null;
                    this._hasAnimatedOnce = true;
                });
                return true;
            }
        } else if (!this._isTimerOn) {
                this._isTimerOn = true;
                if (!this._hasAnimatedOnce) {
                    setTimeout(() => {
                        this._hasAnimatedOnce = true;
                    }, 1000);
                }
            }
        return false;
    }

    public animateWillUnmount(atX: number, atY: number, itemRef: object, itemIndex: number): void {
        (itemRef as UnmountAwareView)._isUnmountedForRecyclerListView = true;
    }

    private _getNativePropObject(x: number, y: number): object {
        const point = { left: x, top: y };

        return !IS_WEB ? point : { style: point };
    }
}
