import {useCallback, useEffect, useLayoutEffect} from 'react';
import {useFocusEffect, useNavigation} from '@react-navigation/native';
import {chatMembershipsHandler} from '@config/synchroniser';
import {getConversationInfo} from '@modules/chats/services';
import {getLatestServerMessageTs} from '@modules/chats/db';
import {
  cleanupAndCloseMessagesSearch,
  clearVisibleChat,
  updateVisibleChatId,
  updateVisibleChatIsChannel,
} from '@modules/chats/store';
import {
  ConversationsUpdaterService,
  UsersUpdaterService,
} from '@modules/chats/instances/updaters';
import {useFeatureFlag} from '@stores/featureFlags';

import {conversationMarker} from '../instances/ConversationMarker';
import {
  clearScrollToMessage,
  resetMessageWindow,
  loadBelowMessagesIfNeeded,
} from '../store/zustand/useGroups';
import {PinnedMessagesUpdaterService} from '../instances/updaters';
import {fileHandler} from '../instances/FileHandler';

interface Params {
  channel: string;
}

/**
 * Setup conversation on mount.
 * - Fetch conversation info from the server if it doesn't exist locally
 * - Fetch group memberships if is not already fetched
 * - Mark conversation as read on screen focus and on blur
 */
export const useSetupConversation = ({channel}: Params) => {
  const isPinMessageEnabled = useFeatureFlag('CHATS_V2_PIN_MESSAGE');
  const navigation = useNavigation();

  /**
   * Fetch and sync conversation info from the server
   */
  const syncConversationWithServer = useCallback(async () => {
    try {
      // Get conversation info from the server and save in the store
      const [conversation] = await getConversationInfo({
        channel,
        fromServer: true,
      });

      updateVisibleChatIsChannel(!!conversation.is_channel);

      // Check if we need to load below messages
      loadBelowMessagesIfNeeded(channel, conversation.latest?.client_msg_id);

      await ConversationsUpdaterService.saveNewConversation(conversation);

      if (conversation.is_channel) {
        chatMembershipsHandler.checkMemberships({
          channel,
          numMembers: conversation.num_members,
        });
      } else {
        if (conversation.other_user) {
          UsersUpdaterService.saveUsers([conversation.other_user]);
        }
      }
    } catch (error) {
      // Do nothing
    }
  }, [channel]);

  // Tie the visibleChat/messageWindow teardown to the screen actually being
  // removed from the stack — not to component unmount. With native-stack +
  // react-native-screens, navigating across groups (e.g. ChatInfo -> Profile)
  // can detach the chats group and fire effect cleanups even though the user
  // is still inside the conversation flow.
  useLayoutEffect(() => {
    updateVisibleChatId(channel);
  }, [channel]);
  useEffect(() => {
    const unsubscribe = navigation.addListener('beforeRemove', () => {
      clearVisibleChat();
      resetMessageWindow(channel);
    });
    return unsubscribe;
  }, [navigation, channel]);

  useEffect(() => {
    // Prioritize this channel for membership fetching
    chatMembershipsHandler.prioritizeChannel(channel);
    fileHandler.setActiveChannel(channel);

    // Run possible side effects of current conversation
    // Trigger this in JS idle time, with timeout 1s to make sure it will be triggered
    const idleId = requestIdleCallback(
      () => {
        syncConversationWithServer();
      },
      {timeout: 1000},
    );

    if (isPinMessageEnabled) {
      // Load pinned messages: use cache/storage first, else fetch from API
      PinnedMessagesUpdaterService.loadOrFetch(channel);
    }

    return () => {
      cancelIdleCallback(idleId);
    };
  }, [channel, isPinMessageEnabled, syncConversationWithServer]);

  useFocusEffect(
    useCallback(() => {
      getLatestServerMessageTs(channel)
        .then(ts => {
          conversationMarker.markConversationAsRead(channel, ts);
        })
        .catch(() => {});
      clearScrollToMessage(channel);

      return () => {
        getLatestServerMessageTs(channel)
          .then(ts => {
            conversationMarker.markConversationAsRead(channel, ts);
          })
          .catch(() => {});
        cleanupAndCloseMessagesSearch();
      };
    }, [channel]),
  );

  return;
};
