import { observer } from "mobx-react-lite";
import React, { useEffect, useRef } from "react";
import { RefreshControl, ScrollView, ScrollViewProps } from "react-native";
import { HScrollView } from "react-native-head-tab-view";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import Animated, {
  runOnJS,
  useAnimatedStyle,
  withTiming,
} from "react-native-reanimated";
import {
  Platform_iOS,
  useColors,
  useDimensions,
  useMeasure,
  useReanimatedValue,
  useSafeArea,
  vs,
} from "../commons";
import { KeyboardProps, Spinner, View } from "../components";
import { tBaseStore } from "../store";

export type ScrollProps = ScrollViewProps & {
  refScrollView?: any;

  reanimated?: boolean;
  isRefreshing?: boolean;
  hideOverflow?: boolean;
  showIndicator?: boolean;
  awareKeyboard?: boolean;

  hViewIndex?: number;

  onRefreshing?: () => void;
};

const AScrollView = Animated.createAnimatedComponent(ScrollView);
const AHScrollView = Animated.createAnimatedComponent(HScrollView);
const AKeyboardAwareScrollView = Animated.createAnimatedComponent(
  KeyboardAwareScrollView
);

export const Scroll = observer((props: ScrollProps) => {
  const {
    refScrollView,

    reanimated,
    isRefreshing,
    hideOverflow,
    showIndicator,
    awareKeyboard,

    hViewIndex,

    children,

    contentContainerStyle,

    onRefreshing,
  } = props;
  const enableRefresh = typeof isRefreshing === "boolean";

  const colors = useColors();

  const renderRefresh = () => {
    if (!enableRefresh) return undefined;

    return (
      <RefreshControl
        colors={[colors.colorApp]}
        tintColor={colors.colorApp}
        titleColor={colors.colorApp}
        refreshing={isRefreshing}
        onRefresh={onRefreshing}
      />
    );
  };

  const renderRefreshControl = () => {
    return <Spinner size={vs(30)} mv={vs(15)} />;
  };

  const MyScroll =
    typeof hViewIndex === "number"
      ? reanimated
        ? AHScrollView
        : HScrollView
      : awareKeyboard && Platform_iOS
      ? reanimated
        ? AKeyboardAwareScrollView
        : KeyboardAwareScrollView
      : reanimated
      ? AScrollView
      : ScrollView;

  return (
    <MyScroll
      {...props}
      ref={refScrollView}
      index={hViewIndex}
      bounces={!hideOverflow}
      enableAutomaticScroll={!tBaseStore.totalModal}
      overScrollMode={"never"}
      scrollEventThrottle={16}
      contentContainerStyle={{ flexGrow: 1 }}
      keyboardShouldPersistTaps={"handled"}
      showsVerticalScrollIndicator={!!showIndicator}
      showsHorizontalScrollIndicator={!!showIndicator}
      refreshControl={
        typeof hViewIndex === "number" ? undefined : renderRefresh()
      }
      {...(enableRefresh
        ? {
            isRefreshing,
            onStartRefresh: onRefreshing,
            renderRefreshControl,
          }
        : {})}
    >
      <View style={[{ flexGrow: 1 }, contentContainerStyle]}>{children}</View>
    </MyScroll>
  );
});

export const ScrollKeyboard = (props: ScrollProps & KeyboardProps) => {
  const { bottom } = useSafeArea();

  const {
    awareKeyboard,
    before = bottom,
    after = vs(16),
    enableAndroid,
    onShow,
    onHide,
  } = props;

  const { height, keyboard, duration } = useDimensions(true);
  const [refView, measureView] = useMeasure(duration);
  const v1H = useReanimatedValue(Platform_iOS ? before : after);
  const v2H = useReanimatedValue(0);
  const yOffsetValue = useRef(0);

  const callback = (show: boolean) => {
    show ? onShow?.() : onHide?.();
  };

  const onLayout = () => {
    measureView(({ y }) => {
      if (y && !keyboard) yOffsetValue.current = Math.max(0, height - y);
    });
  };

  useEffect(() => {
    if (Platform_iOS || enableAndroid) {
      v1H.value = withTiming(
        keyboard ? after : before,
        {
          duration,
        },
        (finished) => {
          finished && runOnJS(callback)(!!keyboard);
        }
      );
      if (awareKeyboard) return;
      v2H.value = withTiming(keyboard ? keyboard - yOffsetValue.current : 0, {
        duration,
      });
    } else callback(!!keyboard);
  }, [before, after, enableAndroid, onShow, onHide, keyboard, duration]);

  const v1S = useAnimatedStyle(
    () => ({
      height: v1H.value,
    }),
    []
  );

  const v2S = useAnimatedStyle(
    () => ({
      height: v2H.value,
    }),
    []
  );

  return (
    <>
      <Scroll {...props}>
        {props.children}
        <View reanimatedStyle={v1S} />
      </Scroll>
      <View refView={refView} reanimatedStyle={v2S} onLayout={onLayout} />
    </>
  );
};
