import {
  Conversation,
  ConversationProperties,
  Message,
} from '@modules/chats/interfaces';
import {
  deleteGroup,
  resetConversationMentioned,
  saveRecentConversations,
  updateGroup,
  useGroups,
} from '@modules/chats/store/zustand/useGroups';
import {
  deleteConversationCascade,
  reduceToLatestMessages,
  removeMentionFromConversation,
  saveNewConversation as saveNewConversationService,
  updateConversationLatest,
  updateConversationProperties,
} from '@modules/chats/db';
import {
  AmplitudeLeftReason,
  LOCAL_INITIAL_VERSION,
} from '@modules/chats/constants';
import {persistedUserId} from '@services/localStorage';
import {logAmplitudeEvent} from '@shared/utils';
import {AMPLITUDE_EVENTS} from '@shared/constants';

import {UnreadsUpdaterService} from './UnreadsUpdaterService';
import {MessageRangesHandler} from '../MessageRangesHandler';
import {PendingMessagesTracker} from '../PendingMessagesTracker';

export class ConversationsUpdaterServiceClass {
  async saveNewConversation(
    data: Conversation,
    options?: {updateStore: boolean},
  ) {
    const {updateStore = true} = options ?? {};
    if (updateStore) {
      updateGroup(data);
    }
    await saveNewConversationService(data);
  }

  async updateConversationsLatest(
    messages: Message[],
    options?: {withMapper?: boolean},
  ) {
    const latestMessages = options?.withMapper
      ? await reduceToLatestMessages(messages)
      : messages;

    return Promise.all(
      latestMessages.map(msg =>
        updateConversationLatest(msg.channel, msg.client_msg_id),
      ),
    );
  }

  async markAsRead(id: string) {
    resetConversationMentioned(id);
    await removeMentionFromConversation(id);
  }

  async leaveGroup({
    channelId,
    triggeredBy,
  }: {
    channelId: string;
    triggeredBy: number;
  }) {
    try {
      // Delete group from the store
      deleteGroup(channelId);

      MessageRangesHandler.clear(channelId);
      PendingMessagesTracker.clearConversation(channelId);

      // Remove unreads info related to the conversation
      UnreadsUpdaterService.deleteItem(channelId);

      // Delete conversation from the DB
      await deleteConversationCascade(channelId);

      const userId = persistedUserId;
      const leftReason =
        userId === triggeredBy
          ? AmplitudeLeftReason.Voluntary
          : AmplitudeLeftReason.Kicked;
      logAmplitudeEvent(AMPLITUDE_EVENTS.CHATS_2_CONVERSATION_LEFT, {
        conversationID: channelId,
        leftReason,
        triggeredBy,
      });
    } catch (error) {
      // Catch error
    }
  }

  async updateProperties(channel: string, properties: ConversationProperties) {
    // Get conversation from the store
    const conversation = useGroups.getState().groups[channel]?.groupInfo;
    if (!conversation) {
      return;
    }

    updateGroup({
      ...conversation,
      properties: {
        ...(conversation.properties || {}),
        ...properties,
      },
    });
    try {
      // Update conversation in the DB
      if (
        properties.notification_status ||
        properties.pinned_at !== undefined || //pinned_at can be null
        properties.marked_unread_at !== undefined
      ) {
        await updateConversationProperties({
          conversationId: channel,
          notificationStatus: properties.notification_status
            ? {
                type: properties.notification_status?.notification_type,
                until: properties.notification_status?.until || null,
              }
            : undefined,
          pinnedAt: properties.pinned_at,
          markedUnreadAt: properties.marked_unread_at,
          version: properties.version || LOCAL_INITIAL_VERSION,
        });
      }
    } catch (error) {
      // Catch error
    }
  }

  saveRecentConversations = (
    data: Parameters<typeof saveRecentConversations>[0],
  ) => {
    saveRecentConversations(data);
  };
}

export const ConversationsUpdaterService =
  new ConversationsUpdaterServiceClass();
