// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import { ReactionModel } from '../messageModifiers/Reactions';
import { ReactionSource } from './ReactionSource';
import { getMessageById } from '../messages/getMessageById';
import { getSourceUuid, isStory } from '../messages/helpers';
import { strictAssert } from '../util/assert';
import { isDirectConversation } from '../util/whatTypeOfConversation';
import { incrementMessageCounter } from '../util/incrementMessageCounter';
import { repeat, zipObject } from '../util/iterables';
import { SendStatus } from '../messages/MessageSendState';
import { UUID } from '../types/UUID';

export async function enqueueReactionForSend({
  emoji,
  messageId,
  remove,
}: Readonly<{
  emoji: string;
  messageId: string;
  remove: boolean;
}>): Promise<void> {
  const message = await getMessageById(messageId);
  strictAssert(message, 'enqueueReactionForSend: no message found');

  const targetAuthorUuid = getSourceUuid(message.attributes);
  strictAssert(
    targetAuthorUuid,
    `enqueueReactionForSend: message ${message.idForLogging()} had no source UUID`
  );

  const targetTimestamp = message.get('sent_at') || message.get('timestamp');
  strictAssert(
    targetTimestamp,
    `enqueueReactionForSend: message ${message.idForLogging()} had no timestamp`
  );

  const timestamp = Date.now();
  const messageConversation = message.getConversation();
  strictAssert(
    messageConversation,
    'enqueueReactionForSend: No conversation extracted from target message'
  );

  const targetConversation =
    isStory(message.attributes) &&
    isDirectConversation(messageConversation.attributes)
      ? window.ConversationController.get(targetAuthorUuid)
      : messageConversation;
  strictAssert(
    targetConversation,
    'enqueueReactionForSend: Did not find a targetConversation'
  );

  const storyMessage = isStory(message.attributes)
    ? message.attributes
    : undefined;

  // Only used in story scenarios, where we use a whole message to represent the reaction
  const storyReactionMessage = storyMessage
    ? new window.Whisper.Message({
        id: UUID.generate().toString(),
        type: 'outgoing',
        conversationId: targetConversation.id,
        sent_at: timestamp,
        received_at: incrementMessageCounter(),
        received_at_ms: timestamp,
        timestamp,
        expireTimer: targetConversation.get('expireTimer'),
        sendStateByConversationId: zipObject(
          targetConversation.getMemberConversationIds(),
          repeat({
            status: SendStatus.Pending,
            updatedAt: Date.now(),
          })
        ),
        storyId: message.id,
        storyReaction: {
          emoji,
          targetAuthorUuid,
          targetTimestamp,
        },
      })
    : undefined;

  const reaction = new ReactionModel({
    emoji,
    fromId: window.ConversationController.getOurConversationIdOrThrow(),
    remove,
    source: ReactionSource.FromThisDevice,
    storyReactionMessage,
    targetAuthorUuid,
    targetTimestamp,
    timestamp,
  });

  await message.handleReaction(reaction, { storyMessage });
}
