import type { ReactElement } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native';
import {
  Animated,
  Easing,
  Platform,
  TouchableWithoutFeedback,
} from 'react-native';
import type { IconName } from '../../Icon';
import Option from './Option';
import { StyledKnot, StyledWrapper } from './StyledSelectorSwitch';

type StatusBadgeType = {
  type: 'status';
};
export type BadgeConfigType = StatusBadgeType;

export type SwitchOptionType<T> = {
  value: T;
  text: string;
  icon: IconName;
  badge?: BadgeConfigType;
};

export interface SelectorSwitchProps<T> {
  /**
   * Array of exactly TWO options to switch between.
   */
  options: [SwitchOptionType<T>, SwitchOptionType<T>];
  /**
   * Current selected value.
   */
  value: T;
  /**
   *  Callback called when an option is pressed.
   */
  onPress?: (value: T) => void;
  /**
   * Additional style.
   */
  style?: StyleProp<ViewStyle>;
  /**
   * Testing id of the component.
   */
  testID?: string;
}

const SelectorSwitch = <T,>({
  options,
  value,
  onPress,
  style,
  testID,
}: SelectorSwitchProps<T>): ReactElement => {
  const [knotWidth, setKnotWidth] = useState(0);
  const [containerWidth, setContainerWidth] = useState(0);
  const animatedValue = useRef(new Animated.Value(0)).current;

  const translateX = animatedValue.interpolate({
    inputRange: [0, 1],
    outputRange: [0, Math.floor(containerWidth - knotWidth)],
  });

  useEffect(() => {
    Animated.timing(animatedValue, {
      toValue: value === options[0].value ? 0 : 1,
      duration: 200,
      easing: Easing.inOut(Easing.ease),
      useNativeDriver: Platform.OS === 'ios' || Platform.OS === 'android',
    }).start();
  }, [value, animatedValue, options]);

  const onContainerLayout = useCallback((e: LayoutChangeEvent) => {
    setContainerWidth(e.nativeEvent.layout.width);
  }, []);

  const onItemLayout = useCallback(
    (e: LayoutChangeEvent, optionValue: T) => {
      if (optionValue === value) {
        setKnotWidth(e.nativeEvent.layout.width);
      }
    },
    [value]
  );

  return (
    <TouchableWithoutFeedback onPress={() => onPress?.(value)} testID={testID}>
      <StyledWrapper onLayout={onContainerLayout} style={style}>
        {options.map((opt, index) => (
          <Option
            {...opt}
            selected={opt.value === value}
            // eslint-disable-next-line react/no-array-index-key
            key={index}
            onLayout={(e) => onItemLayout(e, opt.value)}
            index={index}
          />
        ))}

        <StyledKnot
          style={{
            width: knotWidth,
            transform: [{ translateX }],
          }}
        />
      </StyledWrapper>
    </TouchableWithoutFeedback>
  );
};

export default SelectorSwitch;
