import type { ActionReturnType } from '../../types';

import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
import { applyLangPackDifference, getTranslationFn, requestLangPackDifference } from '../../../util/localization';
import { getPeerTitle } from '../../helpers/peers';
import { addActionHandler, setGlobal } from '../../index';
import {
  addBlockedUser,
  addChats,
  addStoriesForPeer,
  addUsers,
  removeBlockedUser,
  removePeerStory,
  replaceWebPage,
  updateFullWebPage,
  updateLastReadStoryForPeer,
  updatePeerStory,
  updatePeersWithStories,
  updatePoll,
  updateStealthMode,
} from '../../reducers';
import { updateTabState } from '../../reducers/tabs';
import { updateThreadInfo } from '../../reducers/threads';
import {
  selectPeer,
  selectPeerStories,
  selectPeerStory,
  selectTabState,
} from '../../selectors';

addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
  switch (update['@type']) {
    case 'updateEntities': {
      const {
        users, chats, threadInfos, polls, webPages,
      } = update;
      if (users) global = addUsers(global, users);
      if (chats) global = addChats(global, chats);
      if (threadInfos) {
        threadInfos.forEach((threadInfo) => {
          global = updateThreadInfo(global, threadInfo);
        });
      }
      if (polls) {
        polls.forEach((poll) => {
          global = updatePoll(global, poll.summary.id, poll);
        });
      }
      if (webPages) {
        webPages.forEach((webPage) => {
          if (webPage.webpageType === 'full') {
            global = updateFullWebPage(global, webPage.id, webPage);
          } else {
            global = replaceWebPage(global, webPage.id, webPage);
          }
        });
      }
      setGlobal(global);
      break;
    }

    case 'updatePeerBlocked':
      if (update.isBlocked) {
        return addBlockedUser(global, update.id);
      } else if (update.isBlockedFromStories) {
        return global; // Unsupported
      } else {
        return removeBlockedUser(global, update.id);
      }

    case 'updateResetContactList':
      global = {
        ...global,
        contactList: {
          userIds: [],
        },
      };
      setGlobal(global);
      break;

    case 'updateConfig':
      actions.loadConfig();
      break;

    case 'updateAiComposeTones':
      actions.loadAiComposeTones();
      break;

    case 'updateNewAuthorization': {
      // Load more info about this session
      actions.loadAuthorizations();
      break;
    }

    case 'updateFavoriteStickers':
      actions.loadFavoriteStickers();
      break;

    case 'updateRecentStickers':
      actions.loadRecentStickers();
      break;

    case 'updateRecentReactions':
      actions.loadRecentReactions();
      break;

    case 'updateRecentEmojiStatuses':
      actions.loadRecentEmojiStatuses();
      break;

    case 'updateSavedReactionTags':
      actions.loadSavedReactionTags();
      break;

    case 'updateMoveStickerSetToTop': {
      const oldOrder = update.isCustomEmoji ? global.customEmojis.added.setIds : global.stickers.added.setIds;
      if (!oldOrder?.some((id) => id === update.id)) return global;
      const newOrder = [update.id, ...oldOrder.filter((id) => id !== update.id)];
      actions.reorderStickerSets({ order: newOrder, isCustomEmoji: update.isCustomEmoji });
      break;
    }

    case 'updateStickerSets':
      actions.loadStickerSets();
      break;

    case 'updateStickerSetsOrder': {
      // Filter out invalid set IDs, which may be sent by the server
      const order = update.order.filter((setId) => Boolean(global.stickers.setsById[setId]));

      actions.reorderStickerSets({ order, isCustomEmoji: update.isCustomEmoji });
      break;
    }

    case 'updateSavedGifs':
      actions.loadSavedGifs();
      break;

    case 'updatePrivacy':
      global = {
        ...global,
        settings: {
          ...global.settings,
          privacy: {
            ...global.settings.privacy,
            [update.key]: update.rules,
          },
        },
      };
      setGlobal(global);
      break;

    case 'updateWebViewResultSent':
      Object.values(global.byTabId).forEach((tabState) => {
        Object.entries(tabState.webApps.openedWebApps).forEach(([webAppKey, webApp]) => {
          if (webApp.queryId === update.queryId) {
            actions.resetDraftReplyInfo({ tabId: tabState.id });
            actions.closeWebApp({ key: webAppKey, tabId: tabState.id });
          }
        });
      });
      break;

    case 'updateWebPage': {
      const { webPage } = update;
      if (webPage.webpageType === 'full') {
        global = updateFullWebPage(global, webPage.id, webPage);
      } else {
        global = replaceWebPage(global, webPage.id, webPage);
      }
      setGlobal(global);
      break;
    }

    case 'updateStory':
      global = addStoriesForPeer(global, update.peerId, { [update.story.id]: update.story });
      global = updatePeersWithStories(global, { [update.peerId]: selectPeerStories(global, update.peerId)! });
      setGlobal(global);
      break;

    case 'deleteStory':
      global = removePeerStory(global, update.peerId, update.storyId);
      setGlobal(global);
      break;

    case 'updateReadStories':
      global = updateLastReadStoryForPeer(global, update.peerId, update.lastReadId);
      setGlobal(global);
      break;

    case 'updateSentStoryReaction': {
      const { peerId, storyId, reaction } = update;
      const story = selectPeerStory(global, peerId, storyId);
      if (!story) return global;
      global = updatePeerStory(global, peerId, storyId, { sentReaction: reaction });
      setGlobal(global);
      break;
    }

    case 'updateStealthMode':
      global = updateStealthMode(global, update.stealthMode);
      setGlobal(global);
      break;

    case 'updateAttachMenuBots':
      actions.loadAttachBots();
      break;

    case 'updatePremiumFloodWait': {
      actions.processPremiumFloodWait({
        isUpload: update.isUpload,
      });
      break;
    }

    case 'updatePaidReactionPrivacy': {
      global = {
        ...global,
        settings: {
          ...global.settings,
          paidReactionPrivacy: update.private,
        },
      };
      setGlobal(global);
      break;
    }

    case 'updateLangPackTooLong': {
      requestLangPackDifference(update.langCode);
      break;
    }

    case 'updateLangPack': {
      applyLangPackDifference(update.version, update.strings, update.keysToRemove);
      break;
    }

    case 'newMessage': {
      const action = update.message.content?.action;

      if (action?.type === 'starGift' && update.message.isOutgoing) {
        const { gift } = action;
        if (!gift.isAuction || update.message.chatId === SERVICE_NOTIFICATIONS_USER_ID) return undefined;

        const { chatId, id } = update.message;

        if (!chatId || !id) return;

        Object.values(global.byTabId).forEach(({ id: tabId }) => {
          actions.focusMessage({
            chatId,
            messageId: id,
            tabId,
          });
          actions.closeGiftAuctionBidModal({ tabId });
          actions.closeGiftModal({ tabId });

          actions.showNotification({
            icon: 'auction-filled',
            message: {
              key: 'GiftAuctionWonNotification',
              variables: {
                gift: gift.title,
              },
            },
            tabId,
          });

          actions.requestConfetti({ withStars: true, tabId });
        });
        return undefined;
      }

      if (!update.message.isOutgoing && update.message.chatId !== SERVICE_NOTIFICATIONS_USER_ID) return undefined;
      if (action?.type !== 'starGiftUnique') return undefined;
      const actionStarGift = action.gift;

      Object.values(global.byTabId).forEach(({ id: tabId }) => {
        const tabState = selectTabState(global, tabId);
        if (tabState.isWaitingForStarGiftUpgrade) {
          actions.openUniqueGiftBySlug({
            slug: actionStarGift.slug,
            tabId,
          });

          actions.showNotification({
            title: { key: 'GiftUpgradedTitle' },
            message: { key: 'GiftUpgradedDescription' },
            tabId,
          });

          actions.requestConfetti({ withStars: true, tabId });

          global = updateTabState(global, {
            isWaitingForStarGiftUpgrade: undefined,
          }, tabId);
        }

        if (tabState.isWaitingForStarGiftTransfer) {
          const chatId = update.message.chatId;
          const receiver = chatId ? selectPeer(global, chatId) : undefined;
          if (receiver) {
            actions.focusMessage({
              chatId: receiver.id,
              messageId: update.message.id,
              tabId,
            });

            actions.showNotification({
              message: {
                key: 'GiftTransferSuccessMessage',
                variables: {
                  gift: {
                    key: 'GiftUnique',
                    variables: {
                      title: actionStarGift.title,
                      number: actionStarGift.number,
                    },
                  },
                  peer: getPeerTitle(getTranslationFn(), receiver),
                },
              },
              tabId,
            });
          }

          actions.requestConfetti({ withStars: true, tabId });

          global = updateTabState(global, {
            isWaitingForStarGiftTransfer: undefined,
          }, tabId);

          actions.reloadPeerSavedGifts({ peerId: global.currentUserId! });
        }

        if (tabState.giftCraftModal && actionStarGift.isCrafted) {
          global = updateTabState(global, {
            giftCraftModal: {
              ...tabState.giftCraftModal,
              craftResult: { success: true, gift: actionStarGift },
            },
          }, tabId);
        }
      });

      setGlobal(global);
    }
  }

  return undefined;
});
