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

import { ContentHint } from '@signalapp/libsignal-client';

import { getSendOptions } from '../../util/getSendOptions.preload.ts';
import { isGroup } from '../../util/whatTypeOfConversation.dom.ts';
import {
  handleMultipleSendErrors,
  maybeExpandErrors,
} from './handleMultipleSendErrors.std.ts';

import type { ConversationModel } from '../../models/conversations.preload.ts';
import type {
  ConversationQueueJobBundle,
  GroupCallUpdateJobData,
} from '../conversationJobQueue.preload.ts';
import { getUntrustedConversationServiceIds } from './getUntrustedConversationServiceIds.dom.ts';
import { sendToGroup } from '../../util/sendToGroup.preload.ts';
import { wrapWithSyncMessageSend } from '../../util/wrapWithSyncMessageSend.preload.ts';
import { getValidRecipients } from './getValidRecipients.dom.ts';

export async function sendGroupCallUpdate(
  conversation: ConversationModel,
  {
    isFinalAttempt,
    shouldContinue,
    timestamp,
    timeRemaining,
    log,
  }: ConversationQueueJobBundle,
  data: GroupCallUpdateJobData
): Promise<void> {
  const { eraId, urgent } = data;
  const logId = `sendCallUpdate(${conversation.idForLogging()}.${eraId})`;
  if (!shouldContinue) {
    log.info(`${logId}: Ran out of time. Giving up.`);
    return;
  }

  log.info(`${logId}: Starting send`);

  if (!isGroup(conversation.attributes)) {
    log.warn(`${logId}: Conversation is not a group; refusing to send`);
    return;
  }

  const recipients = getValidRecipients(conversation.getRecipients(), {
    log,
    logId,
  });

  const untrustedServiceIds = getUntrustedConversationServiceIds(recipients);
  if (untrustedServiceIds.length) {
    window.reduxActions.conversations.conversationStoppedByMissingVerification({
      conversationId: conversation.id,
      untrustedServiceIds,
    });
    throw new Error(
      `${logId}: Blocked because ${untrustedServiceIds.length} conversation(s) were untrusted. Failing this attempt.`
    );
  }

  if (recipients.length === 0) {
    log.warn(`${logId}: Giving up because there are no valid recipients.`);
    return;
  }

  const sendType = 'callingMessage';

  await conversation.queueJob('sendGroupCallUpdate', async () => {
    const groupV2 = conversation.getGroupV2Info();
    if (!groupV2) {
      log.error(`${logId}: Conversation lacks groupV2 info!`);
      return;
    }

    const sendOptions = await getSendOptions(conversation.attributes);

    try {
      await wrapWithSyncMessageSend({
        conversation,
        logId,
        messageIds: [],
        send: () =>
          sendToGroup({
            contentHint: ContentHint.Default,
            groupSendOptions: {
              groupCallUpdate: { eraId },
              groupV2,
              timestamp,
            },
            messageId: undefined,
            sendOptions,
            sendTarget: conversation.toSenderKeyTarget(),
            sendType,
            urgent,
          }),
        sendType,
        timestamp,
        expirationStartTimestamp: null,
      });
    } catch (error: unknown) {
      await handleMultipleSendErrors({
        errors: maybeExpandErrors(error),
        isFinalAttempt,
        log,
        timeRemaining,
        toThrow: error,
      });
    }
  });
}
