import React, { useState, useCallback, useEffect, useRef } from 'react';
import {
  View,
  TouchableOpacity,
  Image,
  Modal,
  Text,
  FlatList,
  Dimensions,
  Alert,
  ScrollView,
  Linking,
  Platform,
  ActivityIndicator
} from 'react-native';
import {
  GiftedChat,
  Bubble,
  InputToolbar,
  Actions,
  IMessage,
  Send,
  BubbleProps,
  Composer,
  TimeProps,
  MessageProps
} from 'react-native-gifted-chat';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import * as ImagePicker from 'expo-image-picker';
import { useActionSheet } from '@expo/react-native-action-sheet';
import {
  GestureHandlerRootView,
  LongPressGestureHandler,
  Swipeable
} from 'react-native-gesture-handler';
import { AvatarWithInitials, Header, WarningModal } from 'src/components';
import { Colors } from 'src/theme';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { Video } from 'expo-av';
import ChatMessageBox from '../Components/ChatMessageBox';
import ReplyMessageBar from '../Components/ReplyMessageBar';
import { useSharedValue, withTiming } from 'react-native-reanimated';
import { BlurView } from 'expo-blur';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import Clipboard from '@react-native-clipboard/clipboard';
import { trigger } from 'react-native-haptic-feedback';
import ReactModal from 'react-native-modal';
import { storage, StoreType } from 'src/storage';
import {
  usePostDeleteMessageMutation,
  usePostGetChatWithQuery,
  usePostMessagesReadMutation,
  usePostReactToMessageMutation,
  usePostSendMessageMutation
} from '@api/chat';
import { CustomMessage, Message, Reaction } from '../types';
import { API_HOST, WEBSOCKET_URL } from 'src/constants';
import { getFontSize } from 'src/utils';
import ReactionBar from '../Components/ReactionBar';
import OptionsMenu from '../Components/OptionsMenu';
import EmojiSelectorModal from '../Components/EmojiSelectorModal';
import { styles } from './styles';
import SendIcon from 'assets/icons/messages/send.svg';
import { SheetManager } from 'react-native-actions-sheet';
import { NAVIGATION_PAGES } from 'src/types';
import * as Notifications from 'expo-notifications';
import { usePushNotification } from 'src/contexts/PushNotificationContext';
import ReactionsListModal from '../Components/ReactionsListModal';

const options = {
  enableVibrateFallback: true,
  ignoreAndroidSystemSettings: false
};

const reactionEmojis = ['👍', '❤️', '😂', '😮', '😭'];

const ChatScreen = ({ route }: { route: any }) => {
  const { id, name, avatar }: { id: number; name: string; avatar: string | null } = route.params;
  const currentUserId = storage.get('uid', StoreType.STRING) as number;
  const token = storage.get('token', StoreType.STRING) as string;
  const insets = useSafeAreaInsets();
  const [messages, setMessages] = useState<CustomMessage[] | null>();
  const { showActionSheetWithOptions } = useActionSheet();
  const navigation = useNavigation();
  const { data: chatData, isFetching, refetch } = usePostGetChatWithQuery(token, id, -1, -1, true);
  const { mutateAsync: sendMessage } = usePostSendMessageMutation();

  const swipeableRowRef = useRef<Swipeable | null>(null);
  const messageContainerRef = useRef<FlatList<IMessage> | null>(null);
  const [selectedMedia, setSelectedMedia] = useState<any>(null);

  const [replyMessage, setReplyMessage] = useState<CustomMessage | null>(null);
  const [modalInfo, setModalInfo] = useState({
    visible: false,
    type: 'confirm',
    message: '',
    action: () => {}
  });

  const [selectedMessage, setSelectedMessage] = useState<BubbleProps<CustomMessage> | null>(null);
  const [emojiSelectorVisible, setEmojiSelectorVisible] = useState(false);
  const [messagePosition, setMessagePosition] = useState<{
    x: number;
    y: number;
    width: number;
    height: number;
    isMine: boolean;
  } | null>(null);

  const [isModalVisible, setIsModalVisible] = useState(false);
  const [unreadMessageIndex, setUnreadMessageIndex] = useState<number | null>(null);
  const { mutateAsync: markMessagesAsRead } = usePostMessagesReadMutation();
  const { mutateAsync: deleteMessage } = usePostDeleteMessageMutation();
  const { mutateAsync: reactToMessage } = usePostReactToMessageMutation();

  const [highlightedMessageId, setHighlightedMessageId] = useState<number | null>(null);
  const [isRerendering, setIsRerendering] = useState<boolean>(false);
  const [isTyping, setIsTyping] = useState<boolean>(false);

  const messageRefs = useRef<{ [key: string]: any }>({});
  const flatList = useRef<FlatList | null>(null);
  const scrollY = useSharedValue(0);
  const { isSubscribed } = usePushNotification();

  const socket = useRef<WebSocket | null>(null);

  const closeModal = () => {
    setModalInfo({ ...modalInfo, visible: false });
  };

  const dismissChatNotifications = async (chatWithUserId: number) => {
    const { status } = await Notifications.getPermissionsAsync();
    if (status !== 'granted' || !isSubscribed) {
      setModalInfo({
        visible: true,
        type: 'success',
        message:
          'To use this feature we need your permission to access your notifications. You will be redirected to the notification settings screen where you need to enable them.',
        action: () =>
          // @ts-ignore
          navigation.navigate(NAVIGATION_PAGES.MENU_DRAWER, {
            screen: NAVIGATION_PAGES.NOTIFICATIONS
          })
      });
      return;
    }

    const getNotificationData = (notification: Notifications.Notification) => {
      if (Platform.OS === 'android') {
        const data = notification.request.content.data;
        if (data?.params) {
          try {
            return JSON.parse(data.params) ?? {};
          } catch (error) {
            console.error('Error parsing params:', error);
            return {};
          }
        } else {
          Notifications.dismissNotificationAsync(notification.request.identifier);
          return {};
        }
      } else {
        const data = (notification.request.trigger as Notifications.PushNotificationTrigger)
          ?.payload;
        if (data?.params) {
          try {
            return JSON.parse(data.params as string) ?? {};
          } catch (error) {
            console.error('Error parsing params:', error);
            return {};
          }
        }
      }
    };

    const clearNotificationsFromUser = async (userId: number) => {
      const presentedNotifications = await Notifications.getPresentedNotificationsAsync();
      presentedNotifications.forEach((notification) => {
        const parsedParams = getNotificationData(notification);
        const conversation_with_user = parsedParams?.id;

        if (conversation_with_user === userId) {
          Notifications.dismissNotificationAsync(notification.request.identifier);
        }
      });
    };

    await clearNotificationsFromUser(chatWithUserId);

    Notifications.setNotificationHandler({
      handleNotification: async (notification) => {
        let conversation_with_user = 0;
        const parsedParams = getNotificationData(notification);
        conversation_with_user = parsedParams?.id;

        if (conversation_with_user === chatWithUserId) {
          return {
            shouldShowAlert: false,
            shouldPlaySound: false,
            shouldSetBadge: false
          };
        }

        return {
          shouldShowAlert: true,
          shouldPlaySound: false,
          shouldSetBadge: false
        };
      }
    });

    return () => {
      Notifications.setNotificationHandler({
        handleNotification: async () => ({
          shouldShowAlert: true,
          shouldPlaySound: false,
          shouldSetBadge: false
        })
      });
    };
  };

  useEffect(() => {
    let unsubscribe: any;

    const setupNotificationHandler = async () => {
      unsubscribe = await dismissChatNotifications(id);
    };

    setupNotificationHandler();

    return () => {
      if (unsubscribe) unsubscribe();
    };
  }, [id]);

  useEffect(() => {
    socket.current = new WebSocket(WEBSOCKET_URL);

    socket.current.onopen = () => {
      socket.current?.send(JSON.stringify({ token }));
    };

    socket.current.onmessage = (event) => {
      const data = JSON.parse(event.data);
      handleWebSocketMessage(data);
    };

    socket.current.onclose = () => {
      console.log('WebSocket connection closed chat screen');
    };

    return () => {
      socket.current?.close();
    };
  }, [token]);

  const handleWebSocketMessage = (data: any) => {
    switch (data.action) {
      case 'new_message':
        if (data.conversation_with === id) {
          refetch();
        }
        break;
      case 'is_typing':
        if (data.conversation_with === id) {
          setIsTyping(true);
        }
        break;
      case 'stopped_typing':
        if (data.conversation_with === id) {
          setIsTyping(false);
        }
        break;
      case 'new_reaction':
        if (data.conversation_with === id) {
          refetch();
        }
        break;
      default:
        break;
    }
  };

  const sendWebSocketMessage = (action: string) => {
    if (socket.current && socket.current.readyState === WebSocket.OPEN) {
      socket.current.send(JSON.stringify({ action, conversation_with: id }));
    }
  };

  const handleTyping = (isTyping: boolean) => {
    if (isTyping) {
      sendWebSocketMessage('is_typing');
    } else {
      sendWebSocketMessage('stopped_typing');
    }
  };

  const mapApiMessageToGiftedMessage = (message: Message): CustomMessage => {
    return {
      _id: message.id,
      text: message.text,
      createdAt: new Date(message.sent_datetime + 'Z'),
      user: {
        _id: message.sender,
        name: message.sender === id ? name : 'Me'
      },
      replyMessage:
        message.reply_to_id !== -1
          ? {
              text: message.reply_to.text,
              id: message.reply_to.id,
              name: message.reply_to.sender === id ? name : 'Me'
            }
          : null,
      reactions: JSON.parse(message.reactions || '{}'),
      attachment: message.attachement !== -1 ? message.attachement : null,
      pending: message.status === 1,
      sent: message.status === 2,
      received: message.status === 3,
      deleted: message.status === 4
    };
  };

  useFocusEffect(
    useCallback(() => {
      if (chatData?.messages) {
        const mappedMessages = chatData.messages.map(mapApiMessageToGiftedMessage);

        if (unreadMessageIndex === null && Platform.OS === 'ios') {
          const firstUnreadIndex = mappedMessages.findLastIndex(
            (msg) => !msg.received && !msg?.deleted && msg.user._id === id
          );

          if (firstUnreadIndex !== -1) {
            setUnreadMessageIndex(firstUnreadIndex);

            const unreadMarker: any = {
              _id: 'unreadMarker',
              text: 'Unread messages',
              system: true
            };

            mappedMessages.splice(firstUnreadIndex + 1, 0, unreadMarker);
          } else {
            setUnreadMessageIndex(0);
          }
        }
        setMessages(mappedMessages);
      }
    }, [chatData])
  );

  const sentToServer = useRef<Set<number>>(new Set());

  const handleViewableItemsChanged = ({ viewableItems }: { viewableItems: any[] }) => {
    const newViewableUnreadMessages = viewableItems
      .filter(
        (item) =>
          !item.item.received &&
          !item.item.deleted &&
          !item.item.system &&
          item.item.user._id === id &&
          !sentToServer.current.has(item.item._id)
      )
      .map((item) => item.item._id);

    if (newViewableUnreadMessages.length > 0) {
      markMessagesAsRead(
        {
          token,
          from_user: id,
          messages_id: newViewableUnreadMessages
        },
        {
          onSuccess: (res) => {
            newViewableUnreadMessages.forEach((id) => sentToServer.current.add(id));
            // sendWebSocketMessage('messages_read');
            sendWebSocketMessage('new_message');
          }
        }
      );
    }
  };

  const renderSystemMessage = (props: any) => {
    if (props.currentMessage._id === 'unreadMarker') {
      return (
        <View style={styles.unreadMessagesContainer}>
          <Text style={styles.unreadMessagesText}>{props.currentMessage.text}</Text>
        </View>
      );
    }
    return null;
  };

  const clearReplyMessage = () => setReplyMessage(null);

  const handleLongPress = (message: CustomMessage, props: BubbleProps<CustomMessage>) => {
    const messageRef = messageRefs.current[message._id];

    setSelectedMessage(props);
    trigger('impactMedium', options);

    const isMine = message.user._id === +currentUserId;

    if (messageRef) {
      messageRef.measureInWindow((x: number, y: number, width: number, height: number) => {
        const screenHeight = Dimensions.get('window').height;
        const spaceAbove = y - insets.top;
        const spaceBelow = screenHeight - (y + height) - insets.bottom * 2;

        let finalY = y;
        scrollY.value = 0;

        if (isNaN(y) || isNaN(height)) {
          console.error("Invalid measurement values for 'y' or 'height'", { y, height });
          return;
        }

        if (spaceBelow < 160) {
          const extraShift = 160 - spaceBelow;
          finalY -= extraShift;
        }

        if (spaceAbove < 50) {
          const extraShift = 50 - spaceAbove;
          finalY += extraShift;
        }

        if (spaceBelow < 160 || spaceAbove < 50) {
          const targetY = screenHeight / 2 - height / 2;
          scrollY.value = withTiming(finalY - finalY);
        }

        if (height > Dimensions.get('window').height - 200) {
          finalY = 100;
        }

        finalY = isNaN(finalY) ? 0 : finalY;

        setMessagePosition({ x, y: finalY, width, height, isMine });
        setIsModalVisible(true);
      });
    }
  };

  const openEmojiSelector = () => {
    SheetManager.show('emoji-selector');
    trigger('impactLight', options);
  };

  const closeEmojiSelector = () => {
    SheetManager.hide('emoji-selector');
  };

  const handleReactionPress = (emoji: string, messageId: number) => {
    addReaction(messageId, emoji);
  };

  const handleDeleteMessage = (messageId: number) => {
    deleteMessage(
      {
        token,
        message_id: messageId,
        conversation_with_user: id
      },
      {
        onSuccess: () => {
          setMessages((prevMessages) =>
            prevMessages ? prevMessages.filter((msg) => msg._id !== messageId) : []
          );
          // sendWebSocketMessage('message_deleted');
          refetch();
          sendWebSocketMessage('new_message');
        }
      }
    );
  };

  const handleOptionPress = (option: string) => {
    if (!selectedMessage) return;

    switch (option) {
      case 'reply':
        setReplyMessage(selectedMessage.currentMessage);
        setIsModalVisible(false);
        break;
      case 'copy':
        Clipboard.setString(selectedMessage?.currentMessage?.text ?? '');
        setIsModalVisible(false);
        Alert.alert('Copied');
        break;
      case 'delete':
        handleDeleteMessage(selectedMessage.currentMessage?._id);
        setIsModalVisible(false);
        break;
      default:
        break;
    }
    closeEmojiSelector();
  };

  const openReactionList = (
    reactions: { uid: number; name: string; reaction: string }[],
    messageId: number
  ) => {
    SheetManager.show('reactions-list-modal', {
      payload: {
        users: reactions,
        currentUserId: +currentUserId,
        token,
        messageId,
        conversation_with_user: id,
        setMessages,
        sendWebSocketMessage
      } as any
    });
  };

  const renderTimeContainer = (time: TimeProps<CustomMessage>) => {
    const createdAt = new Date(time.currentMessage.createdAt);

    const formattedTime = createdAt.toLocaleTimeString([], {
      hour: '2-digit',
      minute: '2-digit',
      hour12: true
    });

    const hasReactions =
      time.currentMessage.reactions &&
      Array.isArray(time.currentMessage.reactions) &&
      time.currentMessage.reactions.length > 0;

    return (
      <View
        style={{
          flexDirection: 'row',
          justifyContent: hasReactions ? 'space-between' : 'flex-end',
          alignItems: 'center',
          paddingHorizontal: 8,
          paddingBottom: 6,
          flexShrink: 1,
          flexGrow: 1,
          gap: 12
        }}
      >
        {hasReactions && (
          <TouchableOpacity
            style={[
              {
                flexDirection: 'row',
                alignItems: 'center',
                flexShrink: 0,
                backgroundColor:
                  time.position === 'left' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)',
                borderRadius: 12,
                paddingHorizontal: 6,
                paddingVertical: 4,
                gap: 6
              }
            ]}
            onPress={() =>
              Array.isArray(time.currentMessage.reactions) &&
              openReactionList(
                time.currentMessage.reactions.map((reaction) => ({
                  ...reaction,
                  name: reaction.uid === id ? name : 'Me'
                })),
                time.currentMessage._id
              )
            }
          >
            {Object.entries(
              (Array.isArray(time.currentMessage.reactions)
                ? time.currentMessage.reactions
                : []
              ).reduce(
                (acc: Record<string, { count: number }>, { reaction }: { reaction: string }) => {
                  if (!acc[reaction]) {
                    acc[reaction] = { count: 0 };
                  }
                  acc[reaction].count += 1;
                  return acc;
                },
                {}
              )
            ).map(([emoji, { count }]: any) => {
              return (
                <View key={emoji}>
                  <Text style={{}}>
                    {emoji}
                    {(count as number) > 1 ? ` ${count}` : ''}
                  </Text>
                </View>
              );
            })}
          </TouchableOpacity>
        )}
        <View
          style={{
            flexDirection: 'row',
            gap: 4,
            alignItems: 'center',
            alignSelf: 'flex-end'
          }}
        >
          <Text
            style={{
              color: Colors.LIGHT_GRAY,
              fontSize: getFontSize(10),
              fontWeight: '600',
              paddingLeft: 8,
              flexShrink: 0
            }}
          >
            {formattedTime}
          </Text>
          {renderTicks(time.currentMessage)}
        </View>
      </View>
    );
  };

  const renderSelectedMessage = () =>
    selectedMessage && (
      <View
        style={{
          maxHeight: '80%',
          width: messagePosition?.width,
          position: 'absolute',
          top: messagePosition?.y,
          left: messagePosition?.x
        }}
      >
        <ScrollView>
          <Bubble
            {...selectedMessage}
            wrapperStyle={{
              right: { backgroundColor: Colors.DARK_BLUE },
              left: { backgroundColor: Colors.FILL_LIGHT }
            }}
            textStyle={{
              right: { color: Colors.WHITE },
              left: { color: Colors.DARK_BLUE }
            }}
            renderTicks={() => null}
            renderTime={renderTimeContainer}
          />
        </ScrollView>
      </View>
    );

  const handleBackgroundPress = () => {
    setIsModalVisible(false);
    setSelectedMessage(null);
    closeEmojiSelector();
  };

  useFocusEffect(
    useCallback(() => {
      navigation?.getParent()?.setOptions({
        tabBarStyle: {
          display: 'none'
        }
      });
    }, [navigation])
  );

  const onSend = useCallback(
    (newMessages: CustomMessage[] = []) => {
      if (replyMessage) {
        newMessages[0].replyMessage = {
          text: replyMessage.text,
          id: replyMessage._id,
          name: replyMessage.user._id === id ? name : 'Me'
        };
      }
      const message = { ...newMessages[0], pending: true };

      sendMessage(
        {
          token,
          to_uid: id,
          text: message.text,
          reply_to_id: replyMessage ? (replyMessage._id as number) : -1
        },
        {
          onSuccess: () => sendWebSocketMessage('new_message'),
          onError: (err) => console.log('err', err)
        }
      );

      setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [message]));
      clearReplyMessage();
    },
    [replyMessage]
  );

  const openActionSheet = () => {
    const options = ['Open Camera', 'Select from gallery', 'Cancel'];
    const cancelButtonIndex = 2;

    showActionSheetWithOptions(
      {
        options,
        cancelButtonIndex
      },
      async (buttonIndex) => {
        if (buttonIndex === 0) {
          openCamera();
        } else if (buttonIndex === 1) {
          openGallery();
        }
      }
    );
  };

  const openCamera = async () => {
    const permissionResult = await ImagePicker.requestCameraPermissionsAsync();

    if (permissionResult.granted === false) {
      alert('Permission denied to access camera');
      return;
    }

    const result = await ImagePicker.launchCameraAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      quality: 1,
      allowsEditing: true
    });

    if (!result.canceled) {
      const newMedia = {
        _id: Date.now().toString(),
        createdAt: new Date(),
        user: { _id: +currentUserId, name: 'Me' },
        image: result.assets[0].type === 'image' ? result.assets[0].uri : null,
        video: result.assets[0].type === 'video' ? result.assets[0].uri : null
      };
      setMessages((previousMessages) =>
        GiftedChat.append(previousMessages ?? [], [newMedia as any])
      );
    }
  };

  const openGallery = async () => {
    const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();

    if (permissionResult.granted === false) {
      alert('Denied');
      return;
    }

    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsMultipleSelection: true,
      quality: 1
    });

    if (!result.canceled && result.assets) {
      const imageMessages = result.assets.map((asset) => ({
        _id: Date.now().toString() + asset.uri,
        createdAt: new Date(),
        user: { _id: +currentUserId, name: 'Me' },
        image: asset.type === 'image' ? asset.uri : null,
        video: asset.type === 'video' ? asset.uri : null
      }));

      setMessages((previousMessages) =>
        GiftedChat.append(previousMessages ?? [], imageMessages as any[])
      );
    }
  };

  const renderMessageVideo = (props: BubbleProps<CustomMessage>) => {
    const { currentMessage } = props;

    if (currentMessage.video) {
      return (
        <LongPressGestureHandler
          onHandlerStateChange={(event) => handleLongPress(currentMessage, props)}
        >
          <TouchableOpacity
            onPress={() => setSelectedMedia(currentMessage.video)}
            style={styles.mediaContainer}
          >
            <Video
              source={{ uri: currentMessage.video }}
              style={styles.chatMedia}
              useNativeControls
            />
          </TouchableOpacity>
        </LongPressGestureHandler>
      );
    }

    return null;
  };

  const addReaction = (messageId: number, reaction: string) => {
    if (!messages) return;

    const updatedMessages = messages.map((msg: any) => {
      if (msg._id === messageId) {
        const updatedReactions: Reaction[] = [
          ...(Array.isArray(msg.reactions)
            ? msg.reactions?.filter((r: Reaction) => r.uid !== +currentUserId)
            : []),
          { datetime: new Date().toISOString(), reaction: reaction, uid: +currentUserId }
        ];

        return {
          ...msg,
          reactions: updatedReactions
        };
      }
      return msg;
    });

    setMessages(updatedMessages);

    reactToMessage(
      { token, message_id: messageId, reaction: reaction, conversation_with_user: id },
      {
        onSuccess: () => sendWebSocketMessage('new_reaction'),
        onError: (err) => console.log('err', err)
      }
    );

    setIsModalVisible(false);
  };

  const updateRowRef = useCallback(
    (ref: any) => {
      if (
        ref &&
        replyMessage &&
        ref.props.children.props.currentMessage?._id === replyMessage._id
      ) {
        swipeableRowRef.current = ref;
      }
    },
    [replyMessage]
  );

  const renderReplyMessageView = (props: BubbleProps<CustomMessage>) => {
    if (!props.currentMessage) {
      return null;
    }
    const { currentMessage } = props;

    if (!currentMessage || !currentMessage?.replyMessage) {
      return null;
    }

    return (
      <TouchableOpacity
        style={[
          styles.replyMessageContainer,
          {
            backgroundColor:
              currentMessage.user._id === id ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.2)',
            borderColor: currentMessage.user._id === id ? Colors.DARK_BLUE : Colors.WHITE
          }
        ]}
        onPress={() => {
          if (currentMessage?.replyMessage?.id) {
            scrollToMessage(currentMessage.replyMessage.id);
          }
        }}
      >
        <View style={styles.replyContent}>
          <Text
            style={[
              styles.replyAuthorName,
              { color: currentMessage.user._id === id ? Colors.DARK_BLUE : Colors.WHITE }
            ]}
          >
            {currentMessage.replyMessage.name}
          </Text>

          <Text
            numberOfLines={1}
            style={[
              styles.replyMessageText,
              { color: currentMessage.user._id === id ? Colors.DARK_BLUE : Colors.WHITE }
            ]}
          >
            {currentMessage.replyMessage.text}
          </Text>
        </View>
      </TouchableOpacity>
    );
  };

  const scrollToMessage = (messageId: number) => {
    if (!messages) return;

    const messageIndex = messages.findIndex((message) => message._id === messageId);

    if (messageIndex !== -1 && flatList.current) {
      flatList.current.scrollToIndex({
        index: messageIndex,
        animated: true,
        viewPosition: 0.5
      });

      setHighlightedMessageId(messageId);
    }
  };

  useEffect(() => {
    if (highlightedMessageId && isRerendering) {
      setTimeout(() => {
        setHighlightedMessageId(null);
        setIsRerendering(false);
      }, 1500);
    }
  }, [highlightedMessageId, isRerendering]);

  useEffect(() => {
    if (replyMessage && swipeableRowRef.current) {
      swipeableRowRef.current.close();
      swipeableRowRef.current = null;
    }
  }, [replyMessage]);

  const renderMessageImage = (props: any) => {
    const { currentMessage } = props;
    return (
      <TouchableOpacity
        onPress={() => setSelectedMedia(currentMessage.image)}
        style={styles.imageContainer}
      >
        <Image source={{ uri: currentMessage.image }} style={styles.chatImage} resizeMode="cover" />
      </TouchableOpacity>
    );
  };

  const renderTicks = (message: CustomMessage) => {
    if (message.user._id === id) return null;

    return message.received ? (
      <View>
        <MaterialCommunityIcons name="check-all" size={16} color={Colors.WHITE} />
      </View>
    ) : message.sent ? (
      <View>
        <MaterialCommunityIcons name="check" size={16} color={Colors.WHITE} />
      </View>
    ) : message.pending ? (
      <View>
        <MaterialCommunityIcons name="check" size={16} color={Colors.LIGHT_GRAY} />
      </View>
    ) : null;
  };

  const renderBubble = (props: BubbleProps<CustomMessage>) => {
    const { currentMessage } = props;

    if (currentMessage.deleted) {
      const text = currentMessage.text.length
        ? props.currentMessage.text
        : 'This message was deleted';

      return (
        <View>
          <Bubble
            {...props}
            renderTime={() => null}
            currentMessage={{
              ...props.currentMessage,
              text: text
            }}
            renderMessageText={() => (
              <View style={{ paddingHorizontal: 12, paddingVertical: 6 }}>
                <Text style={{ color: Colors.LIGHT_GRAY, fontStyle: 'italic', fontSize: 12 }}>
                  {text}
                </Text>
              </View>
            )}
            wrapperStyle={{
              right: {
                backgroundColor: Colors.DARK_BLUE
              },
              left: {
                backgroundColor: Colors.FILL_LIGHT
              }
            }}
            textStyle={{
              left: {
                color: Colors.DARK_BLUE
              },
              right: {
                color: Colors.WHITE
              }
            }}
          />
        </View>
      );
    }

    const isHighlighted = currentMessage._id === highlightedMessageId;
    const backgroundColor = isHighlighted
      ? Colors.ORANGE
      : currentMessage.user._id === +currentUserId
        ? Colors.DARK_BLUE
        : Colors.FILL_LIGHT;

    return (
      <View
        key={`${currentMessage._id}-${isHighlighted ? 'highlighted' : 'normal'}`}
        ref={(ref) => {
          if (ref && currentMessage) {
            messageRefs.current[currentMessage._id] = ref;
          }
        }}
        collapsable={false}
      >
        <Bubble
          {...props}
          wrapperStyle={{
            right: {
              backgroundColor: backgroundColor
            },
            left: {
              backgroundColor: backgroundColor
            }
          }}
          textStyle={{
            left: {
              color: Colors.DARK_BLUE
            },
            right: {
              color: Colors.FILL_LIGHT
            }
          }}
          onLongPress={() => handleLongPress(currentMessage, props)}
          renderTicks={() => null}
          renderTime={renderTimeContainer}
        />
      </View>
    );
  };

  const renderInputToolbar = (props: any) => (
    <InputToolbar
      {...props}
      renderActions={() =>
        // <Actions
        //   icon={() => <MaterialCommunityIcons name="plus" size={28} color={Colors.DARK_BLUE} />}
        //   // onPressActionButton={openActionSheet}
        // />
        null
      }
      containerStyle={{
        backgroundColor: Colors.FILL_LIGHT
      }}
    />
  );

  const renderScrollToBottom = () => {
    return (
      <TouchableOpacity
        style={{
          position: 'absolute',
          bottom: -20,
          right: -20,
          backgroundColor: Colors.DARK_BLUE,
          borderRadius: 20,
          padding: 8
        }}
        onPress={() => {
          if (flatList.current) {
            flatList.current.scrollToIndex({ index: 0, animated: true });
          }
        }}
      >
        <MaterialCommunityIcons name="chevron-down" size={24} color={Colors.WHITE} />
      </TouchableOpacity>
    );
  };

  const shouldUpdateMessage = (
    props: MessageProps<IMessage>,
    nextProps: MessageProps<IMessage>
  ) => {
    setIsRerendering(true);
    const currentId = nextProps.currentMessage._id;
    return currentId === highlightedMessageId;
  };

  return (
    <SafeAreaView
      edges={['top']}
      style={{
        height: '100%'
      }}
    >
      <View style={{ paddingHorizontal: '5%' }}>
        <Header
          label={name}
          rightElement={
            <TouchableOpacity
              onPress={() =>
                navigation.navigate(
                  ...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId: id }] as never)
                )
              }
            >
              {avatar ? (
                <Image source={{ uri: API_HOST + avatar }} style={styles.avatar} />
              ) : (
                <AvatarWithInitials
                  text={
                    name
                      .split(/ (.+)/)
                      .map((n) => n[0])
                      .join('') ?? ''
                  }
                  flag={API_HOST + 'flag.png'}
                  size={30}
                  fontSize={12}
                />
              )}
            </TouchableOpacity>
          }
        />
      </View>

      <GestureHandlerRootView style={styles.container}>
        {messages ? (
          <GiftedChat
            messages={messages as CustomMessage[]}
            listViewProps={{
              ref: flatList,
              showsVerticalScrollIndicator: false,
              initialNumToRender: 30,
              onViewableItemsChanged: handleViewableItemsChanged,
              viewabilityConfig: { itemVisiblePercentThreshold: 50 },
              initialScrollIndex: unreadMessageIndex ?? 0,
              onScrollToIndexFailed: (info: any) => {
                const wait = new Promise((resolve) => setTimeout(resolve, 300));
                wait.then(() => {
                  flatList.current?.scrollToIndex({
                    index: info.index,
                    animated: true,
                    viewPosition: 0.5
                  });
                });
              }
            }}
            renderSystemMessage={renderSystemMessage}
            onSend={(newMessages: CustomMessage[]) => onSend(newMessages)}
            user={{ _id: +currentUserId, name: 'Me' }}
            renderBubble={renderBubble}
            renderMessageImage={renderMessageImage}
            renderInputToolbar={renderInputToolbar}
            renderCustomView={renderReplyMessageView}
            isCustomViewBottom={false}
            messageContainerRef={messageContainerRef}
            minComposerHeight={34}
            onInputTextChanged={(text) => handleTyping(text.length > 0)}
            isTyping={isTyping}
            renderSend={(props) => (
              <View
                style={{
                  flexDirection: 'row',
                  height: '100%',
                  alignItems: 'center',
                  justifyContent: 'center',
                  paddingHorizontal: 14
                }}
              >
                {props.text?.trim() && (
                  <Send
                    {...props}
                    containerStyle={{
                      justifyContent: 'center'
                    }}
                  >
                    <SendIcon fill={Colors.DARK_BLUE} />
                  </Send>
                )}
                {!props.text?.trim() && <SendIcon fill={Colors.LIGHT_GRAY} />}
              </View>
            )}
            textInputProps={{ ...styles.composer, selectionColor: Colors.LIGHT_GRAY }}
            placeholder=""
            renderMessage={(props) => (
              <ChatMessageBox
                {...(props as MessageProps<CustomMessage>)}
                updateRowRef={updateRowRef}
                setReplyOnSwipeOpen={setReplyMessage}
              />
            )}
            renderChatFooter={() => (
              <ReplyMessageBar clearReply={clearReplyMessage} message={replyMessage} />
            )}
            // renderMessageVideo={renderMessageVideo}
            renderAvatar={null}
            maxComposerHeight={100}
            renderComposer={(props) => <Composer {...props} />}
            keyboardShouldPersistTaps="handled"
            renderChatEmpty={() => (
              <View style={styles.emptyChat}>
                <Text
                  style={styles.emptyChatText}
                >{`No messages yet.\nFeel free to start the conversation.`}</Text>
              </View>
            )}
            shouldUpdateMessage={shouldUpdateMessage}
            scrollToBottom={true}
            scrollToBottomComponent={renderScrollToBottom}
            scrollToBottomStyle={{ backgroundColor: 'transparent' }}
            parsePatterns={(linkStyle) => [
              {
                type: 'url',
                style: { color: Colors.ORANGE, textDecorationLine: 'underline' },
                onPress: (url: string) => Linking.openURL(url),
                onLongPress: (url: string) => {
                  Clipboard.setString(url ?? '');
                  Alert.alert('Link copied');
                }
              }
            ]}
          />
        ) : (
          <ActivityIndicator size="large" color={Colors.DARK_BLUE} />
        )}

        <Modal visible={!!selectedMedia} transparent={true}>
          <View style={styles.modalContainer}>
            {selectedMedia && selectedMedia?.includes('.mp4') ? (
              <Video
                source={{ uri: selectedMedia }}
                style={styles.fullScreenMedia}
                useNativeControls
              />
            ) : (
              <Image source={{ uri: selectedMedia ?? '' }} style={styles.fullScreenMedia} />
            )}
            <TouchableOpacity onPress={() => setSelectedMedia(null)} style={styles.closeButton}>
              <MaterialCommunityIcons name="close" size={30} color="white" />
            </TouchableOpacity>
          </View>
        </Modal>

        <ReactModal
          isVisible={isModalVisible}
          onBackdropPress={handleBackgroundPress}
          style={styles.reactModalContainer}
          animationIn="fadeIn"
          animationOut="fadeOut"
          useNativeDriver
          backdropColor="transparent"
        >
          <BlurView
            intensity={80}
            style={styles.modalBackground}
            experimentalBlurMethod="dimezisBlurView"
          >
            <TouchableOpacity
              style={styles.modalBackground}
              activeOpacity={1}
              onPress={handleBackgroundPress}
            >
              <ReactionBar
                messagePosition={messagePosition}
                selectedMessage={selectedMessage}
                reactionEmojis={reactionEmojis}
                handleReactionPress={handleReactionPress}
                openEmojiSelector={openEmojiSelector}
              />
              {renderSelectedMessage()}
              <OptionsMenu
                selectedMessage={selectedMessage}
                handleOptionPress={handleOptionPress}
                messagePosition={messagePosition}
              />
              <EmojiSelectorModal
                visible={emojiSelectorVisible}
                selectedMessage={selectedMessage}
                addReaction={addReaction}
                closeEmojiSelector={closeEmojiSelector}
              />
            </TouchableOpacity>
          </BlurView>
        </ReactModal>

        <WarningModal
          isVisible={modalInfo.visible}
          onClose={closeModal}
          type={modalInfo.type}
          message={modalInfo.message}
          action={() => {
            modalInfo.action();
            closeModal();
          }}
        />
        <ReactionsListModal />
      </GestureHandlerRootView>
      <View
        style={{
          height: insets.bottom,
          backgroundColor: Colors.FILL_LIGHT
        }}
      />
    </SafeAreaView>
  );
};

export default ChatScreen;
