import React, { useRef, useState, useEffect } from 'react';
import {
  Animated,
  Dimensions,
  PanResponder,
  StyleSheet,
  Easing,
  TouchableWithoutFeedback,
  Pressable,
  Platform,
} from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { SBoxAnimated } from '../../s-components/layout/s-box-animated';
import { SBox } from '../../s-components/layout/s-box';
import { theme } from '../../../app/theme';
import { Icon } from '../icon';
import { withNavigation } from '../../hoc/with-navigation';
import { fp as _ } from '../../utils/fp';

const { height: DEVICE_HEIGHT, width: DEVICE_WIDTH } = Dimensions.get('window');

type TProps = {
  render?: () => React.ReactElement;
  navigation: any;
  children?: React.ReactElement;
};

const TopSliderShadeComponent: React.FC<TProps> = props => {
  const { navigation, render, children } = props;
  const [hidden, setHidden] = useState(true);
  const [pressed, setPressed] = useState(false);

  const translateY = useRef(new Animated.Value(-DEVICE_HEIGHT));

  const offsetY = useRef({ y: -DEVICE_HEIGHT });

  const inited = useRef(false);

  const navigationSub = useRef<any>();

  const animateToTop = (duration?: number) => {
    offsetY.current = { y: -DEVICE_HEIGHT };
    Animated.timing(translateY.current, {
      toValue: -DEVICE_HEIGHT,
      duration: duration || 350,
      useNativeDriver: true,
    }).start(() => {
      setHidden(true);
    });
  };

  const hideScreen = () =>
    setTimeout(() => {
      if (!inited.current) return;
      animateToTop(0);
    }, 800);

  useEffect(() => {
    navigationSub.current = navigation.addListener('blur', hideScreen);
    inited.current = true;

    return () => {
      if (navigationSub.current && _.isFunction(navigationSub.current)) {
        navigationSub.current();
      }
      inited.current = false;
    };
  }, [navigation, inited.current]);

  const animateToBottom = () => {
    offsetY.current = { y: 0 };
    Animated.timing(translateY.current, {
      toValue: 0,
      easing: Easing.bezier(0.19, 1.0, 0.22, 1.0),
      duration: 400,
      useNativeDriver: true,
    }).start();
  };

  const panResponder = PanResponder.create({
    onPanResponderMove: (e, gestureState) => {
      const { dy } = gestureState;
      if (dy > -DEVICE_HEIGHT && offsetY.current.y < 0) {
        let translationY = dy + offsetY.current.y;
        translateY.current.setValue(translationY);
      }
    },
    onPanResponderRelease: (e, gestureState) => {
      const { dy } = gestureState;
      if (dy < -150) {
        // close on swipe
        animateToTop();
      } else if (dy < 50 && dy > -50) {
        // small swipe
        animateToBottom();
      } else if (dy > -150 && dy < 100) {
        // bounce to top
        animateToTop();
      } else {
        // open on swipe
        animateToBottom();
      }
    },
    onMoveShouldSetPanResponder: (e, gestureState) => {
      return Math.abs(gestureState.dx) >= 1 || Math.abs(gestureState.dy) >= 1;
    },
    onPanResponderGrant: () => {
      setHidden(false);
    },
  });

  const isAndroid = Platform.OS === 'android';
  const opacityInterpolate = translateY.current.interpolate({
    inputRange: [-DEVICE_HEIGHT, -DEVICE_HEIGHT / 2, 0],
    outputRange: [0, 1, 1],
  });

  const scaleInterpolate = translateY.current.interpolate({
    inputRange: [-DEVICE_HEIGHT, -DEVICE_HEIGHT + 100, 0],
    outputRange: [0, 0.2, 1],
  });

  const translateYInterpolate = translateY.current.interpolate({
    inputRange: [-DEVICE_HEIGHT, 0],
    outputRange: [-325, 0],
  });

  const borderRadiusInterpolate = translateY.current.interpolate({
    inputRange: [-DEVICE_HEIGHT, 0],
    outputRange: [DEVICE_WIDTH / 4, 0],
  });

  const isIos = Platform.OS === 'ios';

  return (
    <>
      <SBoxAnimated
        style={[
          StyleSheet.absoluteFill,
          {
            // backgroundColor: 'red',
            height: 80,
            top: isAndroid ? 34 : 64,
            width: 80,
            opacity: 0.5,
            left: '50%',
            marginLeft: -40,
            borderRadius: 8,
          },
        ]}
        {...panResponder.panHandlers}
      >
        <Pressable
          onPress={() => {
            setHidden(() => {
              animateToBottom();
              return false;
            });
          }}
        >
          {({ pressed }) => (
            <SBox height={100} opacity={pressed ? 0.6 : 0}>
              <LinearGradient
                colors={theme.gradients.topSliderShadeAvatar}
                locations={[1, 0]}
                style={[
                  StyleSheet.absoluteFill,
                  {
                    height: 80,
                    borderRadius: 8,
                  },
                ]}
              />
            </SBox>
          )}
        </Pressable>
      </SBoxAnimated>
      {!hidden ? (
        <SBoxAnimated
          style={[
            StyleSheet.absoluteFill,
            {
              height: DEVICE_HEIGHT,
              top: 0,
              left: 0,
              backgroundColor: theme.colors.steelGray,
              zIndex: 10,
              transform: [
                { translateY: translateYInterpolate },
                { scale: scaleInterpolate },
              ],
              opacity: opacityInterpolate,
              borderRadius: borderRadiusInterpolate,
            },
          ]}
          {...panResponder.panHandlers}
        >
          <SBoxAnimated
            style={[
              {
                width: '100%',
                position: 'absolute',
                bottom: 0,
                left: 0,
                borderRadius: borderRadiusInterpolate,
                overflow: 'hidden',
                zIndex: -1,
              },
            ]}
          >
            <LinearGradient
              style={{
                height: 547,
              }}
              colors={theme.gradients.topSliderShade}
            />
          </SBoxAnimated>

          <TouchableWithoutFeedback
            onPress={() => {
              if (!isAndroid) {
                animateToTop();
              }
            }}
            onPressIn={() => setPressed(true)}
            onPressOut={() => {
              setPressed(false);
              if (isAndroid) {
                animateToTop();
              }
            }}
            testID="close-slider"
          >
            <SBox
              position="absolute"
              zIndex={9999}
              left={23}
              top={isIos ? 61 : 37}
              opacity={pressed ? 0.7 : 1}
              width={44}
              height={44}
            >
              <Icon name="close-2" size={32} color="white" />
            </SBox>
          </TouchableWithoutFeedback>
          {render ? render() : null}
          {children || null}
        </SBoxAnimated>
      ) : null}
    </>
  );
};

export const TopSliderShade = withNavigation(TopSliderShadeComponent);
