import React, { useCallback, useContext, useEffect, useRef } from 'react';
import {
  BackHandler,
  Dimensions,
  KeyboardAvoidingView,
  Modal,
  PanResponder,
  Platform,
  Pressable,
  StyleSheet,
  TouchableOpacity,
  View,
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ApplicationContext, MiniAppContext } from '../Context';
import { BottomSheetParams } from './types';
import { Colors, Radius, Spacing, Styles } from '../Consts';
import { Text } from '../Text';
import { Icon } from '../Icon';
import { useHeaderHeight } from '@react-navigation/elements';
import Animated, {
  Easing,
  Extrapolate,
  interpolate,
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
  withTiming,
} from 'react-native-reanimated';
import layoutStyles from '../Layout/styles';

const BottomSheet: React.FC<BottomSheetParams> = props => {
  const { theme, navigator } = useContext(ApplicationContext);
  const context = useContext<any>(MiniAppContext);
  const heightDevice = Dimensions.get('screen').height;
  const action = useRef<undefined | string>(undefined);
  const insets = useSafeAreaInsets();
  const heightHeader = useHeaderHeight();
  const keyboardOffset = heightHeader - Math.min(insets.bottom, 21);

  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;

  const {
    screen: Screen,
    options,
    useNativeModal = false,
    surface,
    barrierDismissible = false,
    draggable = true,
    useBottomInset = true,
    useKeyboardAvoidingView = true,
    keyboardVerticalOffset,
    useDivider = true,
    footerComponent,
    leftOptions,
  }: BottomSheetParams = props.route.params;

  const translateY = useSharedValue(heightDevice);

  const openAnimation = useCallback(() => {
    translateY.value = withTiming(0, {
      duration: 350,
      easing: Easing.bezier(0.05, 0.7, 0.1, 1),
    });
  }, [translateY]);

  const closeAnimation = useCallback(
    (callback = () => {}) => {
      translateY.value = withTiming(
        heightDevice,
        {
          duration: 200,
          easing: Easing.bezier(0.3, 0.0, 0.8, 0.15),
        },
        () => runOnJS(callback)(),
      );
    },
    [heightDevice, translateY],
  );

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => draggable,
      onMoveShouldSetPanResponder: (_, gestureState) =>
        draggable && gestureState.dy > 0,
      onPanResponderMove: (_, gestureState) => {
        if (gestureState.dy > 0) {
          translateY.value = gestureState.dy;
        }
      },
      onPanResponderRelease: (_, gestureState) => {
        if (gestureState.dy > 100) {
          action.current = 'gesture';
          onDismiss(true);
        } else {
          translateY.value = withSpring(0, {
            damping: 20,
            mass: 1,
            stiffness: 100,
            overshootClamping: false,
            energyThreshold: 1e-10,
          });
        }
      },
    }),
  ).current;

  let Container: any = View;
  if (useNativeModal) {
    Container = Modal;
  }
  let backgroundColor = theme.colors.background.default;
  if (surface) {
    backgroundColor = theme.colors.background.surface;
  }

  /**
   * emit dismiss event
   */
  useEffect(() => {
    translateY.value = heightDevice;
    openAnimation();
    return () => {
      props.route.params?.onDismiss?.(action.current);
    };
  }, [heightDevice, openAnimation, props.route.params, translateY]);

  /**
   * handler dismiss
   */
  const onDismiss = useCallback(
    (force = false, callback?: () => void) => {
      if (barrierDismissible && !force) {
        return;
      }
      closeAnimation(() => {
        navigator?.pop();
        runOnJS(() => {
          callback?.();
        })();
      });
    },
    [barrierDismissible, closeAnimation, navigator],
  );

  /**
   * on request close
   */
  const onRequestClose = useCallback(
    (callback?: () => void) => {
      onDismiss(true, callback);
    },
    [onDismiss],
  );

  useEffect(() => {
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      () => {
        onDismiss();
        return true;
      },
    );
    return () => backHandler.remove();
  }, [barrierDismissible, onDismiss]);

  /**
   * render header
   */
  const renderHeader = useCallback(() => {
    return (
      <View {...panResponder.panHandlers}>
        <View style={{ height: 16 }}>
          <View style={styles.indicator} />
        </View>
        <View
          style={[
            styles.header,
            useDivider && {
              borderBottomColor: theme.colors.border.default,
              borderBottomWidth: 1,
            },
          ]}
        >
          {leftOptions?.onPressIconLeft ? (
            <TouchableOpacity
              style={styles.iconButton}
              onPress={() => {
                onDismiss(true, leftOptions.onPressIconLeft);
              }}
            >
              <Icon source={leftOptions.iconLeft ?? 'ic_back'} />
            </TouchableOpacity>
          ) : null}

          {options.header ? (
            <View style={Styles.flex}>{options.header}</View>
          ) : (
            <>
              {!leftOptions ? <View style={styles.iconButton} /> : null}
              <Text
                style={[Styles.flex, { textAlign: 'center' }]}
                numberOfLines={1}
                typography="header_default_bold"
              >
                {options.title ?? ''}
              </Text>
            </>
          )}
          <TouchableOpacity
            style={styles.iconButton}
            onPress={() => {
              action.current = 'icon_close';
              onDismiss(true);
            }}
          >
            <Icon source="navigation_close" />
          </TouchableOpacity>
        </View>
      </View>
    );
  }, [
    onDismiss,
    leftOptions,
    options.header,
    options.title,
    panResponder.panHandlers,
    theme.colors.border.default,
    useDivider,
  ]);

  const animatedStyle = useAnimatedStyle(() => {
    return {
      transform: [{ translateY: translateY.value }],
    };
  });

  const animatedOverlayStyle = useAnimatedStyle(() => {
    return {
      opacity: interpolate(
        translateY.value,
        [0, heightDevice],
        [1, 0],
        Extrapolate.CLAMP,
      ),
    };
  });

  return (
    <Container
      transparent
      visible={true}
      onRequestClose={() => {
        onDismiss();
      }}
      style={StyleSheet.absoluteFillObject}
      isModalKit={true}
    >
      <KeyboardAvoidingView
        behavior={Platform.select({
          ios: 'position',
          android: undefined,
        })}
        keyboardVerticalOffset={keyboardVerticalOffset ?? keyboardOffset}
        enabled={useKeyboardAvoidingView}
        contentContainerStyle={styles.container}
        style={styles.container}
      >
        <Pressable
          style={StyleSheet.absoluteFillObject}
          onPress={() => {
            action.current = 'touch';
            onDismiss();
          }}
        >
          <Animated.View style={[styles.overlay, animatedOverlayStyle]} />
        </Pressable>

        <Animated.View
          style={[
            animatedStyle,
            {
              backgroundColor,
              borderTopLeftRadius: Radius.M,
              borderTopRightRadius: Radius.M,
              overflow: 'hidden',
            },
            showBaseLineDebug && styles.debugBaseLine,
          ]}
        >
          {renderHeader()}
          <Screen
            {...props}
            {...props.route.params}
            onRequestClose={onRequestClose}
          />
          {footerComponent && (
            <View
              style={[
                layoutStyles.shadow,
                {
                  paddingBottom: Spacing.S,
                  backgroundColor: theme.colors.background.surface,
                },
              ]}
            >
              {footerComponent}
            </View>
          )}
          {useBottomInset && (
            <View
              style={{
                height: Math.min(insets.bottom, 21),
                backgroundColor: backgroundColor,
              }}
            />
          )}
        </Animated.View>
      </KeyboardAvoidingView>
    </Container>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'flex-end',
  },
  overlay: {
    flex: 1,
    backgroundColor: 'rgba(0, 0, 0, 0.6)',
  },
  indicator: {
    width: 40,
    height: 4,
    borderRadius: Radius.S,
    backgroundColor: Colors.black_06,
    position: 'absolute',
    alignSelf: 'center',
    top: Spacing.S,
  },
  header: {
    height: 56,
    flexDirection: 'row',
    alignItems: 'center',
  },
  iconButton: {
    width: 24,
    height: 24,
    alignItems: 'center',
    justifyContent: 'center',
    marginHorizontal: Spacing.M,
  },
  debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
});

export default BottomSheet;
