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

import { copyTextToClipboard } from '../../../util/clipboard';
import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { omit } from '../../../util/iteratees';
import * as langProvider from '../../../util/oldLangProvider';
import { callApi } from '../../../api/gramjs';
import { addTabStateResetterAction } from '../../helpers/meta';
import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { addStoriesForPeer } from '../../reducers';
import { updateTabState } from '../../reducers/tabs';
import {
  selectCurrentViewedStory,
  selectPeer,
  selectPeerFirstStoryId,
  selectPeerFirstUnreadStoryId,
  selectPeerStories,
  selectStoryListForViewer,
  selectTabState,
} from '../../selectors';
import { fetchChatByUsername } from '../api/chats';
import { getPeerStarsForMessage } from '../api/messages';

addActionHandler('openStoryViewer', async (global, actions, payload): Promise<void> => {
  const {
    peerId, storyId, isSinglePeer, isSingleStory, isPrivate, isArchive, origin, tabId = getCurrentTabId(),
  } = payload;

  const peer = selectPeer(global, peerId);
  if (!peer) {
    return;
  }

  const tabState = selectTabState(global, tabId);
  const peerStories = selectPeerStories(global, peerId);

  if (storyId && (!peerStories || !peerStories.byId[storyId])) {
    const result = await callApi('fetchPeerStoriesByIds', { peer, ids: [storyId] });

    if (!result) {
      return;
    }
    global = getGlobal();
    global = addStoriesForPeer(global, peerId, result.stories);
  }

  const storyList = tabState.storyViewer.storyList
    || selectStoryListForViewer(global, peerId, storyId, isSingleStory, isSinglePeer, isPrivate, isArchive);

  global = updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      peerId,
      storyId: storyId || selectPeerFirstUnreadStoryId(global, peerId) || selectPeerFirstStoryId(global, peerId),
      isSinglePeer,
      isPrivate,
      isArchive,
      isSingleStory,
      viewModal: undefined,
      origin,
      storyList,
    },
  }, tabId);
  setGlobal(global);
});

addActionHandler('openStoryViewerByUsername', async (global, actions, payload): Promise<void> => {
  const {
    username, storyId, origin, tabId = getCurrentTabId(),
  } = payload;

  const chat = await fetchChatByUsername(global, username);

  if (!chat) {
    return;
  }

  actions.openStoryViewer({
    peerId: chat.id,
    storyId,
    isSinglePeer: true,
    isSingleStory: true,
    origin,
    tabId,
  });
});

addActionHandler('closeStoryViewer', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};
  const {
    isMuted, isRibbonShown, isArchivedRibbonShown, storyId,
  } = selectTabState(global, tabId).storyViewer;

  if (!storyId) return global;

  global = updateTabState(global, {
    storyViewer: {
      isMuted,
      isRibbonShown,
      isArchivedRibbonShown,
      lastViewedByPeerId: undefined,
      storyList: undefined,
    },
  }, tabId);

  return global;
});

addActionHandler('setStoryViewerMuted', (global, actions, payload): ActionReturnType => {
  const {
    isMuted,
    tabId = getCurrentTabId(),
  } = payload;

  return updateTabState(global, {
    storyViewer: {
      ...selectTabState(global, tabId).storyViewer,
      isMuted,
    },
  }, tabId);
});

addActionHandler('toggleStoryRibbon', (global, actions, payload): ActionReturnType => {
  const { isShown, isArchived, tabId = getCurrentTabId() } = payload;

  const orderedIds = global.stories.orderedPeerIds[isArchived ? 'archived' : 'active'];
  if (!orderedIds?.length) {
    return global;
  }

  return updateTabState(global, {
    storyViewer: {
      ...selectTabState(global, tabId).storyViewer,
      [isArchived ? 'isArchivedRibbonShown' : 'isRibbonShown']: isShown,
    },
  }, tabId);
});

addActionHandler('openPreviousStory', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};
  const tabState = selectTabState(global, tabId);
  const {
    peerId, storyId, isSinglePeer, isSingleStory, storyList,
  } = tabState.storyViewer;

  if (isSingleStory || !storyList) {
    actions.closeStoryViewer({ tabId });
    return undefined;
  }

  if (!peerId || !storyId) {
    return undefined;
  }

  const peer = selectPeer(global, peerId);
  const peerStories = selectPeerStories(global, peerId);
  if (!peerStories || !peer) {
    return undefined;
  }

  const { peerIds: orderedPeerIds, storyIdsByPeerId } = storyList;
  const peerStoryIds = storyIdsByPeerId[peerId] ?? [];
  const currentStoryIndex = peerStoryIds.indexOf(storyId);
  let previousStoryIndex: number;
  let previousPeerId: string;

  if (currentStoryIndex > 0) {
    previousStoryIndex = currentStoryIndex - 1;
    previousPeerId = peerId;
  } else {
    const previousPeerIdIndex = orderedPeerIds.indexOf(peerId) - 1;
    if (isSinglePeer || previousPeerIdIndex < 0) {
      return undefined;
    }

    previousPeerId = orderedPeerIds[previousPeerIdIndex];
    previousStoryIndex = (storyIdsByPeerId?.[previousPeerId]?.length || 1) - 1;
  }

  const previousStoryId = storyIdsByPeerId?.[previousPeerId]?.[previousStoryIndex];
  if (!previousStoryId) {
    return undefined;
  }

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      peerId: previousPeerId,
      storyId: previousStoryId,
    },
  }, tabId);
});

addActionHandler('openNextStory', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};
  const tabState = selectTabState(global, tabId);
  const {
    peerId, storyId, isSinglePeer, isSingleStory, storyList,
  } = tabState.storyViewer;
  if (isSingleStory || !storyList) {
    actions.closeStoryViewer({ tabId });
    return undefined;
  }

  if (!peerId || !storyId) {
    return undefined;
  }

  const peer = selectPeer(global, peerId);
  const peerStories = selectPeerStories(global, peerId);
  if (!peerStories || !peer) {
    return undefined;
  }

  const { peerIds: orderedPeerIds, storyIdsByPeerId } = storyList;
  const peerStoryIds = storyIdsByPeerId[peerId] ?? [];
  const currentStoryIndex = peerStoryIds.indexOf(storyId);
  let nextStoryIndex: number;
  let nextPeerId: string;

  if (currentStoryIndex < peerStoryIds.length - 1) {
    nextStoryIndex = currentStoryIndex + 1;
    nextPeerId = peerId;
  } else {
    const nextPeerIdIndex = orderedPeerIds.indexOf(peerId) + 1;
    if (isSinglePeer || nextPeerIdIndex > orderedPeerIds.length - 1) {
      actions.closeStoryViewer({ tabId });
      return undefined;
    }

    nextPeerId = orderedPeerIds[nextPeerIdIndex];
    nextStoryIndex = 0;
  }

  const nextStoryId = storyIdsByPeerId?.[nextPeerId]?.[nextStoryIndex];
  if (!nextStoryId) {
    return undefined;
  }

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      peerId: nextPeerId,
      storyId: nextStoryId,
    },
  }, tabId);
});

addActionHandler('openStoryViewModal', (global, actions, payload): ActionReturnType => {
  const { storyId, tabId = getCurrentTabId() } = payload;
  const tabState = selectTabState(global, tabId);

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      viewModal: {
        storyId,
        nextOffset: '',
        isLoading: true,
      },
    },
  }, tabId);
});

addActionHandler('closeStoryViewModal', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};
  const tabState = selectTabState(global, tabId);

  return updateTabState(global, {
    storyViewer: omit(tabState.storyViewer, ['viewModal']),
  }, tabId);
});

addActionHandler('copyStoryLink', async (global, actions, payload): Promise<void> => {
  const { peerId, storyId, tabId = getCurrentTabId() } = payload;

  const peer = selectPeer(global, peerId);
  if (!peer) {
    return;
  }

  const link = await callApi('fetchStoryLink', { peer, storyId });
  if (!link) {
    return;
  }

  copyTextToClipboard(link);
  actions.showNotification({
    message: langProvider.oldTranslate('LinkCopied'),
    tabId,
  });
});

addActionHandler('sendMessage', async (global, actions, payload): Promise<void> => {
  const { tabId = getCurrentTabId() } = payload;
  const { storyId, peerId: storyPeerId } = selectCurrentViewedStory(global, tabId);
  const isStoryReply = Boolean(storyId && storyPeerId);

  if (!isStoryReply) {
    return;
  }
  const messagePriceInStars = await getPeerStarsForMessage(global, storyPeerId!);
  if (messagePriceInStars === undefined) return;

  const { gif, sticker, isReaction } = payload;

  let message: string;
  if (gif) {
    message = 'Story.Tooltip.GifSent';
  } else if (sticker) {
    message = 'Story.Tooltip.StickerSent';
  } else if (isReaction) {
    message = 'Story.Tooltip.ReactionSent';
  } else {
    message = 'Story.Tooltip.MessageSent';
  }

  actions.showNotification({
    message: langProvider.oldTranslate(message),
    actionText: langProvider.oldTranslate('Story.ToastViewInChat'),
    action: [{
      action: 'closeStoryViewer',
      payload: undefined,
    }, {
      action: 'openChat',
      payload: { id: storyPeerId },
    }],
    tabId,
  });
});

addActionHandler('openStoryPrivacyEditor', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};
  const tabState = selectTabState(global, tabId);

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      isPrivacyModalOpen: true,
    },
  }, tabId);
});

addActionHandler('closeStoryPrivacyEditor', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};
  const tabState = selectTabState(global, tabId);

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      isPrivacyModalOpen: false,
    },
  }, tabId);
});

addActionHandler('openStealthModal', (global, actions, payload): ActionReturnType => {
  const { targetPeerId, tabId = getCurrentTabId() } = payload;

  return updateTabState(global, {
    storyStealthModal: {
      targetPeerId,
    },
  }, tabId);
});

addTabStateResetterAction('closeStealthModal', 'storyStealthModal');

addActionHandler('clearStoryViews', (global, actions, payload): ActionReturnType => {
  const { isLoading, tabId = getCurrentTabId() } = payload || {};

  const tabState = selectTabState(global, tabId);

  if (!tabState.storyViewer.viewModal) return global;

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      viewModal: {
        ...tabState.storyViewer.viewModal,
        views: undefined,
        isLoading,
        nextOffset: '',
      },
    },
  }, tabId);
});

addActionHandler('updateStoryView', (global, actions, payload): ActionReturnType => {
  const {
    userId, isUserBlocked, areStoriesBlocked, tabId = getCurrentTabId(),
  } = payload;

  const tabState = selectTabState(global, tabId);
  const { viewModal } = tabState.storyViewer;
  if (!viewModal?.storyId) return undefined;

  const updatedViews = viewModal?.views?.map((view) => {
    if (view.peerId === userId) {
      return {
        ...view,
        isUserBlocked: isUserBlocked || undefined,
        areStoriesBlocked: areStoriesBlocked || undefined,
      };
    }

    return view;
  });

  return updateTabState(global, {
    storyViewer: {
      ...tabState.storyViewer,
      viewModal: {
        ...viewModal,
        views: updatedViews,
      },
    },
  }, tabId);
});

addActionHandler('closeBoostModal', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};

  return updateTabState(global, {
    boostModal: undefined,
  }, tabId);
});

addActionHandler('closeBoostStatistics', (global, actions, payload): ActionReturnType => {
  const { tabId = getCurrentTabId() } = payload || {};

  return updateTabState(global, {
    boostStatistics: undefined,
  }, tabId);
});
