import React, { memo } from "react";
import { ActivityIndicator, StyleSheet } from "react-native";

import Animated, {
  useAnimatedReaction,
  useAnimatedStyle,
  useDerivedValue,
  useSharedValue,
  SharedValue,
} from "react-native-reanimated";

import { useRefreshDerivedValue } from "./hooks";
import { RefreshControlProps, RefreshTypeEnum } from "./types";

type RefreshControlContainerProps = {
  top: number;
  refreshHeight: number;
  overflowPull: number;
  opacityValue: SharedValue<number>;
  refreshValue: SharedValue<number>;
  isRefreshing: SharedValue<boolean>;
  isRefreshingWithAnimation: SharedValue<boolean>;
  pullExtendedCoefficient: number;
  renderContent?: (refreshProps: RefreshControlProps) => React.ReactElement;
  refreshControlColor?: string;
};

const RefreshControlContainer: React.FC<RefreshControlContainerProps> = ({
  top,
  refreshHeight,
  overflowPull,
  opacityValue,
  refreshValue,
  isRefreshing,
  isRefreshingWithAnimation,
  pullExtendedCoefficient,
  renderContent,
  refreshControlColor = "#999999",
}) => {
  const refreshType = useSharedValue<RefreshTypeEnum>(RefreshTypeEnum.Idle);
  const progress = useDerivedValue(() => {
    if (isRefreshingWithAnimation.value) return 1;
    return Math.min(refreshValue.value / refreshHeight, 1);
  });
  const tranYValue = useSharedValue(0);

  useRefreshDerivedValue(tranYValue, {
    animatedValue: refreshValue,
    refreshHeight,
    overflowPull,
    pullExtendedCoefficient,
  });

  useAnimatedReaction(
    () => {
      return {
        _progress: progress.value,
        _isRefreshing: isRefreshing.value,
        _isRefreshingWithAnimation: isRefreshingWithAnimation.value,
      };
    },
    ({ _progress, _isRefreshing, _isRefreshingWithAnimation }) => {
      if (_isRefreshing !== _isRefreshingWithAnimation) {
        refreshType.value = _isRefreshing
          ? RefreshTypeEnum.Pending
          : RefreshTypeEnum.Finish;
        return;
      }
      if (_isRefreshing) {
        refreshType.value = RefreshTypeEnum.Refreshing;
      } else {
        refreshType.value =
          _progress < 1 ? RefreshTypeEnum.Cancel : RefreshTypeEnum.Success;
      }
    },
    [refreshHeight]
  );

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

  const _renderContent = () => {
    const _props = makeChildProps();
    if (renderContent) {
      return React.cloneElement(renderContent(_props), makeChildProps());
    }
    return (
      <RefreshControlNormal
        {..._props}
        refreshControlColor={refreshControlColor}
      />
    );
  };

  const makeChildProps = () => {
    return {
      refreshValue,
      refreshType,
      progress,
    };
  };

  return (
    <Animated.View
      style={[
        styles.container,
        { top: top - refreshHeight, height: refreshHeight },
        animatedStyle,
      ]}
    >
      {_renderContent()}
    </Animated.View>
  );
};

export default RefreshControlContainer;

const RefreshControlNormal = memo<RefreshControlProps>(
  function RefreshControlNormal({ refreshControlColor }) {
    return (
      <Animated.View style={styles.baseControl}>
        <ActivityIndicator color={refreshControlColor} />
      </Animated.View>
    );
  }
);

const styles = StyleSheet.create({
  baseControl: {
    alignItems: "center",
    flex: 1,
    justifyContent: "center",
    paddingTop: 10,
  },
  container: {
    left: 0,
    position: "absolute",
    right: 0,
    width: "100%",
  },
  textStyle: {
    marginTop: 4,
    fontSize: 13,
    textAlign: "center",
  },
});
