import React, {memo, useEffect, useRef} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {IconChevronLeft, IconMicrophone} from '@tabler/icons-react-native';
import LottieView from 'lottie-react-native';
import Animated, {
  Extrapolation,
  cancelAnimation,
  interpolate,
  runOnJS,
  useAnimatedReaction,
  useAnimatedStyle,
  useSharedValue,
  withDelay,
  withRepeat,
  withTiming,
} from 'react-native-reanimated';
import {Typography} from '@components';
import {formatSecondsToTime} from '@modules/chat/utils';
import {
  useAudioRecording,
  useAudioRecordingAnimated,
} from '@modules/chats/contexts';
import {AUDIO_ANIMATED_VALUES} from '@modules/chats/constants';
import {windowDimensions} from '@shared/constants';
import {useTheme} from '@shared/theme';

import DeleteVoices from '../../../../assets/deleteVoices.json';
import {styles} from './styles';

const {width} = windowDimensions;

export const VoiceRecordingPanelDefault = memo(() => {
  const {theme} = useTheme();
  const {t} = useTranslation();
  const lottieRef = useRef<Nullable<LottieView>>(null);
  const isLottieStarted = useRef(false);
  const opacityValue = useSharedValue(0);
  const isAnimationStarted = useSharedValue(0);
  const timerRef = useRef<Nullable<NodeJS.Timeout>>(undefined);
  const {isLocked, isActive, isCanceling, isActiveAnimated, translationValueX} =
    useAudioRecordingAnimated();
  const {audioDurationSeconds} = useAudioRecording();
  const time = formatSecondsToTime(audioDurationSeconds, {
    minutesFormat: 'm',
  });

  const animatedAudioSessionPanelStyle = useAnimatedStyle(() => {
    if (!_WORKLET) {
      return {
        opacity: 0,
        transform: [{translateX: width}],
      };
    }

    return {
      opacity: interpolate(isActiveAnimated.value, [0, 0.8, 1], [0, 0, 1]),
      transform: [
        {translateX: interpolate(isActiveAnimated.value, [0, 1], [width, 0])},
      ],
    };
  });

  const swipeToCancelAnimatedStyle = useAnimatedStyle(() => {
    if (!_WORKLET) {
      return {
        opacity: 0,
        transform: [{translateX: 0}],
      };
    }

    return {
      opacity:
        interpolate(
          translationValueX.value,
          [0, -AUDIO_ANIMATED_VALUES.cancelThreshold],
          [1, 0],
        ) - isCanceling.value,
      transform: [
        {
          translateX: interpolate(
            translationValueX.value,
            [0, -AUDIO_ANIMATED_VALUES.cancelThreshold],
            [0, -(AUDIO_ANIMATED_VALUES.cancelThreshold / 4)],
            Extrapolation.CLAMP,
          ),
        },
      ],
    };
  });

  const lottieWrapperAnimatedStyle = useAnimatedStyle(() => {
    if (!_WORKLET) {
      return {
        opacity: 0,
      };
    }

    return {
      opacity: opacityValue.value,
    };
  });

  const staticMicWrapperAnimatedStyle = useAnimatedStyle(() => {
    if (!_WORKLET) {
      return {
        opacity: 1,
      };
    }

    return {
      opacity: 1 - isAnimationStarted.value,
    };
  });

  const runLottieAnimation = () => {
    if (lottieRef.current) {
      lottieRef.current.play();
    }
  };

  const resetLottieAnimation = () => {
    if (lottieRef.current) {
      lottieRef.current.reset();
    }
  };

  const runBlinkingAnimation = () => {
    if (timerRef.current) {
      clearTimeout(timerRef.current);
    }

    lottieRef.current?.reset();
    cancelAnimation(opacityValue);

    opacityValue.value = 0;
    isAnimationStarted.value = 0;

    timerRef.current = setTimeout(() => {
      opacityValue.value = withRepeat(
        withTiming(1, {
          duration: AUDIO_ANIMATED_VALUES.micBlinkingAnimationDuration,
        }),
        -1,
        true,
      );
      isAnimationStarted.value = 1;
      clearTimeout(timerRef.current!);
    }, 1000);
  };

  useAnimatedReaction(
    () => !isCanceling.value && !!isActive.value && !isLocked.value,
    val => {
      if (val) {
        runOnJS(runBlinkingAnimation)();
      } else {
        runOnJS(resetLottieAnimation)();
        opacityValue.value = 0;

        isAnimationStarted.value = withDelay(
          AUDIO_ANIMATED_VALUES.cancelingAnimationDurationMs,
          withTiming(0, {duration: 0}),
        );
        cancelAnimation(opacityValue);
      }
    },
    [],
  );

  useAnimatedReaction(
    () => isCanceling.value,
    val => {
      if (val) {
        opacityValue.value = 1;
        runOnJS(runLottieAnimation)();
      }
    },
    [],
  );

  useEffect(() => {
    return () => {
      cancelAnimation(opacityValue);
      resetLottieAnimation();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <>
      <Animated.View style={[styles.container, animatedAudioSessionPanelStyle]}>
        <View style={styles.timeWithLottie}>
          <View style={styles.micWrapper}>
            <Animated.View
              style={[styles.lottieMicWrapper, lottieWrapperAnimatedStyle]}>
              <LottieView
                ref={lottieRef}
                source={DeleteVoices}
                loop={false}
                duration={AUDIO_ANIMATED_VALUES.cancelingAnimationDurationMs}
                resizeMode={'cover'}
                style={styles.lottie}
                onAnimationFinish={() => {
                  isLottieStarted.current = false;
                }}
              />
            </Animated.View>
            <Animated.View style={staticMicWrapperAnimatedStyle}>
              <IconMicrophone color={theme.text.neutral.lighter} />
            </Animated.View>
          </View>
          <View style={styles.timerContainer}>
            <Typography variant="s">{time}</Typography>
          </View>
        </View>
        <Animated.View
          style={[styles.swipeToCancel, swipeToCancelAnimatedStyle]}>
          <Typography variant={'s'}>
            {t('chat.recording.swipe_to_cancel')}
          </Typography>
          <IconChevronLeft />
        </Animated.View>
      </Animated.View>
    </>
  );
});
