import React, { useCallback, useEffect, useRef, useState } from "react";
import { AccessibilityProps, Animated } from "react-native";
import { Pressable, Factory, Flex, Text, HStack } from "native-base";
import { FlipColors } from "@flip.id/ui-kit";

const PressableAnimated = Animated.createAnimatedComponent(Pressable);

const AnimatedView = Factory(Animated.View);
// @ts-ignore
const AnimatedPressable = Factory(PressableAnimated);

export interface IToggleSwitch {
  onChange?: (result: boolean) => void;
  isOn?: boolean;
  isDisableActiveColor?: boolean;
  onLabel?: string;
  offLabel?: string;
  testID?: string;
}

export const ToggleSwitch: React.FC<IToggleSwitch & AccessibilityProps> = (
  props
) => {
  const { isOn, isDisableActiveColor, onChange, onLabel, offLabel, ...rest } =
    props;
  const [isActive, setIsOn] = useState(isOn ?? false);
  const toggleLeft = useRef(new Animated.Value(0)).current;
  const toggleWidth = useRef(new Animated.Value(24)).current;
  const initialRender = useRef(true);

  const toggleOnOff = useCallback(() => {
    setIsOn((val) => !val);
  }, []);

  useEffect(() => {
    setIsOn(isOn ?? false);
  }, [isOn]);

  function composeAnimation(
    animatedValue: Animated.Value,
    value: number,
    duration: number
  ) {
    return Animated.timing(animatedValue, {
      toValue: value,
      duration: duration,
      useNativeDriver: false,
    });
  }

  const runAnimationAndSendCallback = useCallback(
    (_isActive: boolean) => {
      if (initialRender.current) {
        initialRender.current = false;
        return;
      }
      Animated.sequence([
        composeAnimation(toggleWidth, _isActive ? 50 : 24, 100),
        Animated.parallel([
          composeAnimation(toggleLeft, _isActive ? 1 : 0, 200),
          composeAnimation(toggleWidth, _isActive ? 24 : 50, 200),
        ]),
        composeAnimation(toggleWidth, 24, 100),
      ]).start();
      onChange?.(_isActive);
    },
    [toggleLeft, initialRender, onChange, toggleWidth]
  );

  useEffect(() => {
    runAnimationAndSendCallback(isActive);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isActive]);

  return (
    <AnimatedPressable
      h="7"
      w="54"
      p="0.5"
      position="relative"
      rounded="full"
      alignItems="center"
      justifyContent="center"
      overflow="hidden"
      onPress={toggleOnOff}
      style={{
        backgroundColor: isDisableActiveColor
          ? FlipColors.neutral.Container
          : toggleLeft.interpolate({
              inputRange: [0, 1],
              outputRange: [
                FlipColors.neutral.Container,
                FlipColors.flipOrange.Main,
              ],
            }),
      }}
      {...rest}
    >
      <AnimatedView
        top="0.5"
        position="absolute"
        rounded="full"
        bg="white"
        borderColor={
          isDisableActiveColor
            ? "neutral.BorderAndDisabled"
            : isActive
            ? "flipOrange.Minus1"
            : "neutral.BorderAndDisabled"
        }
        borderWidth="1.5"
        h="6"
        style={{
          width: toggleWidth,
          left: toggleLeft.interpolate({
            inputRange: [0, 1],
            /**
             * this will move from 2px (left) to calculation of
             * (ToggleSwitch width - Padding Size - Circle Width)
             */
            outputRange: [2, 54 - 2 - 24],
          }),
        }}
      />
      <HStack
        w="full"
        space="0.5"
        justifyContent="space-between"
        alignItems="center"
      >
        <Flex w="6" h="6" alignItems="center" justifyContent="center">
          <Text
            fontSize="xs"
            textAlign="center"
            lineHeight="25"
            fontWeight="bold"
            color={!isActive ? "neutral.MainText" : "neutral.SecondaryText"}
          >
            {offLabel}
          </Text>
        </Flex>
        <Flex w="6" h="6" alignItems="center" justifyContent="center">
          <Text
            fontSize="xs"
            textAlign="center"
            lineHeight="25"
            fontWeight="bold"
            color={isActive ? "neutral.MainText" : "neutral.SecondaryText"}
          >
            {onLabel}
          </Text>
        </Flex>
      </HStack>
    </AnimatedPressable>
  );
};

export default ToggleSwitch;
