import {
  RoomRecord,
  RoomWithData,
} from '../../../../../../../../server-services/query-records/room-records';
import {
  SidebarGroup,
  SidebarResource,
  UNGROUPPED_GROUP_ID,
} from '../../../../../../../../server-services/query-records/sidebar-records';
import { WorkspaceSubscriptionRoomEventRecord } from '../../../../../../../../server-services/query-records/workspace-records';
import {
  getRoomQuery,
  getSidebarGroupQuery,
  getSidebarResourceQuery,
  getSidebarUngrouppedQuery,
} from '../../../../../../../../server-services/querys';
import { SeenCacheRecord } from '../../../../../custom-cache-reset-logic';
import { WorkspaceChangeSubscriptionSpecificHandler } from '../types';

export let onModifyRoomEventSubscriptionHandler: WorkspaceChangeSubscriptionSpecificHandler = (
  cache,
  event: WorkspaceSubscriptionRoomEventRecord
) => {
  if (event.groupId !== undefined || event.ordering !== undefined) {
    let sidebarRes: SidebarResource = cache.getCacheDataByRequest({
      query: getSidebarResourceQuery,
      variables: event,
    });
    if (sidebarRes) {
      if (event.groupId !== undefined) {
        let oldGroup = sidebarRes.groupId;
        sidebarRes.groupId = event.groupId;

        // remove from the old container
        let container: SidebarResource[] | null = null;
        if (oldGroup == UNGROUPPED_GROUP_ID) {
          container = cache.getCacheDataByRequest({
            query: getSidebarUngrouppedQuery,
            variables: {},
          });
        } else {
          let group: SidebarGroup = cache.getCacheDataByRequest({
            query: getSidebarGroupQuery,
            variables: {
              id: oldGroup,
            },
          });
          if (group) {
            container = group.resources;
          } else {
            console.warn('could not find the source group in the cache', event);
          }
        }

        if (container) {
          // it should be in the prev container
          let index = container.indexOf(sidebarRes);

          if (index > -1) {
            // remove the element from its old container
            container.splice(index, 1);
          } else {
            console.warn('could not find the element in its original container in the cache');
          }
        }

        // push into the new container
        if (event.groupId == UNGROUPPED_GROUP_ID) {
          cache
            .getCacheDataByRequest({ query: getSidebarUngrouppedQuery, variables: {} })
            .push(sidebarRes);
        } else {
          let group: SidebarGroup = cache.getCacheDataByRequest({
            query: getSidebarGroupQuery,
            variables: {
              id: event.groupId,
            },
          });
          if (group) {
            group.resources.push(sidebarRes);
          } else {
            console.warn('could not find the source group in the cache', event);
          }
        }
      }
      if (event.ordering !== undefined) {
        sidebarRes.ordering = event.ordering;
      }
    } else {
      console.warn('could not found the resource in the cache, but got modified event');
    }
  }

  let room: RoomRecord | RoomWithData = cache.getCacheDataByRequest({
    query: getRoomQuery,
    variables: {
      id: event.id,
    },
  });
  // seen subscriptption does not contain data
  if (room) {
    if (event.data) {
      (<RoomWithData>room).data = event.data;
    }
    if (event.seenMessageId) {
      room.seenMessageId = event.seenMessageId;
    }
    if (event.topMessageId) {
      room.topMessageId = event.topMessageId;
    }
    if (event.nanoSessionsAdded) {
      room.nanoSessions = Object.assign(room.nanoSessions, event.nanoSessionsAdded);
    }
    if (event.nanoSessionsRemoved) {
      event.nanoSessionsRemoved.forEach((element) => {
        delete room.nanoSessions[element];
      });
    }
    if (event.nanoSessionsReset) {
      room.nanoSessions = event.nanoSessionsReset;
    }
  } else {
    console.warn('could not found the room in the cache, but got modified event');
  }

  if (event.peerSeenIdsAdded) {
    // update the seen status of the messages

    // init the message if it is not exists
    let seenCacheData: SeenCacheRecord = cache.getCacheData('seen')[event.id];
    if (!seenCacheData) {
      seenCacheData = {
        messages: {},
        users: {},
      };

      cache.getCacheData('seen')[event.id] = seenCacheData;
    }

    for (const [userId, messageId] of Object.entries(event.peerSeenIdsAdded)) {
      // remove the prev message if exists
      let prevMessageId = seenCacheData.users[userId];

      if (prevMessageId) {
        if (seenCacheData.messages[prevMessageId]) {
          let findUserIndex = seenCacheData.messages[prevMessageId].indexOf(userId);
          if (findUserIndex > -1) {
            seenCacheData.messages[prevMessageId].splice(findUserIndex, 1);
            if (seenCacheData.messages[prevMessageId].length == 0) {
              delete seenCacheData.messages[prevMessageId];
            }
          }
        }
      }

      // add the user to the new message
      if (seenCacheData.messages[messageId]) {
        // user should not be there, so we do not need to check if it is already exists
        seenCacheData.messages[messageId].push(userId);
      } else {
        seenCacheData.messages[messageId] = [userId];
      }

      // add the message to the user
      seenCacheData.users[userId] = event.peerSeenIdsAdded[userId];
    }
  }
};
