import React, {
  createContext,
  useCallback,
  useContext,
  useMemo,
  useState,
} from 'react';
import {
  Easing,
  SharedValue,
  useAnimatedStyle,
  useDerivedValue,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';
import {CHATS_SPACING} from '@modules/chats/utils';

const ANIMATION_CONFIG = {
  duration: 250,
  easing: Easing.out(Easing.cubic),
};

type AnimationContextType = {
  dialog: Nullable<SharedValue<number>>;
  giphyDialog: Nullable<SharedValue<number>>;
};

type DialogVisibilityContextType = {
  isDialogVisible: boolean;
  setIsDialogVisible: (value: boolean) => void;
  isGiphyDialogVisible: boolean;
  setIsGiphyDialogVisible: (value: boolean) => void;
};

const AnimationContext = createContext<AnimationContextType>({
  dialog: null,
  giphyDialog: null,
});

const DialogVisibilityContext = createContext<DialogVisibilityContextType>({
  isDialogVisible: false,
  setIsDialogVisible: () => null,
  isGiphyDialogVisible: false,
  setIsGiphyDialogVisible: () => null,
});

export const useChatAnimations = () => useContext(AnimationContext);
export const useDialogVisibility = () => useContext(DialogVisibilityContext);

export const useGiphyDialog = () => {
  const {giphyDialog} = useChatAnimations();
  const {isGiphyDialogVisible, setIsGiphyDialogVisible} = useDialogVisibility();

  const showGiphyDialog = useCallback(() => {
    if (giphyDialog) {
      setIsGiphyDialogVisible(true);
      giphyDialog.value = withTiming(1, ANIMATION_CONFIG);
    }
  }, [giphyDialog, setIsGiphyDialogVisible]);

  const hideGiphyDialog = useCallback(() => {
    if (giphyDialog) {
      setIsGiphyDialogVisible(false);
      giphyDialog.value = withTiming(0, ANIMATION_CONFIG);
    }
  }, [giphyDialog, setIsGiphyDialogVisible]);

  return {showGiphyDialog, hideGiphyDialog, isGiphyDialogVisible};
};

export const useGiphyDialogAnimatedStyle = () => {
  const {giphyDialog} = useChatAnimations();

  const animatedHeight = useDerivedValue(() => {
    return giphyDialog
      ? giphyDialog.value * CHATS_SPACING.giphyDialogHeight
      : 0;
  }, [giphyDialog]);

  const animatedOpacity = useDerivedValue(() => {
    return giphyDialog ? giphyDialog.value : 0;
  }, [giphyDialog]);

  return useAnimatedStyle(() => {
    return {
      height: animatedHeight.value,
      opacity: animatedOpacity.value,
    };
  }, [animatedHeight, animatedOpacity]);
};

export const useSelectFileDialog = () => {
  const {dialog} = useChatAnimations();
  const {isDialogVisible, setIsDialogVisible} = useDialogVisibility();

  const showDialog = useCallback(() => {
    if (dialog) {
      setIsDialogVisible(true);
      dialog.value = withTiming(
        CHATS_SPACING.attachmentDialogHeight,
        ANIMATION_CONFIG,
      );
    }
  }, [dialog, setIsDialogVisible]);

  const hideDialog = useCallback(() => {
    if (dialog) {
      setIsDialogVisible(false);
      dialog.value = withTiming(0, ANIMATION_CONFIG);
    }
  }, [dialog, setIsDialogVisible]);

  return useMemo(
    () => ({showDialog, hideDialog, isDialogVisible}),
    [showDialog, hideDialog, isDialogVisible],
  );
};

export const useDialogAnimatedStyle = () => {
  const {dialog} = useChatAnimations();

  return useAnimatedStyle(() => {
    return {
      height: dialog ? dialog.value : 0,
    };
  }, [dialog]);
};

export const AnimationProvider: React.FC<{children: React.ReactNode}> = ({
  children,
}) => {
  const dialog = useSharedValue(0);
  const giphyDialog = useSharedValue(0);
  const [isDialogVisible, setIsDialogVisible] = useState(false);
  const [isGiphyDialogVisible, setIsGiphyDialogVisible] = useState(false);

  const animationValue = useMemo(
    () => ({
      dialog,
      giphyDialog,
    }),
    [dialog, giphyDialog],
  );

  const visibilityValue = useMemo(
    () => ({
      isDialogVisible,
      setIsDialogVisible,
      isGiphyDialogVisible,
      setIsGiphyDialogVisible,
    }),
    [isDialogVisible, isGiphyDialogVisible],
  );

  return (
    <AnimationContext.Provider value={animationValue}>
      <DialogVisibilityContext.Provider value={visibilityValue}>
        {children}
      </DialogVisibilityContext.Provider>
    </AnimationContext.Provider>
  );
};
