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

import type { PrimaryDevice } from '@signalapp/mock-server';
import { Proto } from '@signalapp/mock-server';
import createDebug from 'debug';
import type { Page } from 'playwright';
import assert from 'node:assert';
import * as durations from '../../util/durations/index.std.ts';
import type { App } from '../playwright.node.ts';
import { Bootstrap } from '../bootstrap.node.ts';
import { acceptConversation } from '../helpers.node.ts';

export const debug = createDebug('mock:test:edit');

describe('unknown contacts', function (this: Mocha.Suite) {
  this.timeout(durations.MINUTE);

  let bootstrap: Bootstrap;
  let app: App;
  let page: Page;
  let unknownContact: PrimaryDevice;

  beforeEach(async () => {
    bootstrap = new Bootstrap({ contactCount: 1, unknownContactCount: 1 });
    await bootstrap.init();
    app = await bootstrap.link();
    page = await app.getWindow();

    const { unknownContacts } = bootstrap;
    [unknownContact] = unknownContacts as [PrimaryDevice];
  });

  afterEach(async function (this: Mocha.Context) {
    if (!bootstrap) {
      return;
    }

    await bootstrap.maybeSaveLogs(this.currentTest, app);
    await app.close();
    await bootstrap.teardown();
  });

  it('blocks incoming calls from unknown contacts & shows message request', async () => {
    const { desktop } = bootstrap;

    debug('sending calling offer message');
    await unknownContact.sendRaw(desktop, {
      content: {
        callMessage: {
          offer: {
            id: BigInt(Math.floor(Math.random() * 1e10)),
            type: Proto.CallMessage.Offer.Type.OFFER_AUDIO_CALL,
            opaque: new Uint8Array(0),
          },
          answer: null,
          iceUpdate: null,
          busy: null,
          hangup: null,
          destinationDeviceId: null,
          opaque: null,
        },
      },
      pniSignatureMessage: null,
      senderKeyDistributionMessage: null,
    });

    debug('opening conversation');
    const leftPane = page.locator('#LeftPane');

    const conversationListItem = leftPane.getByRole('button', {
      name: 'Chat with Unknown contact',
    });
    await conversationListItem.getByText('Message Request').click();

    const conversationStack = page.locator('.Inbox__conversation-stack');
    await conversationStack.getByText('Missed voice call').waitFor();

    debug('accepting message request');
    await page.getByText('message you and share your name').waitFor();
    await acceptConversation(page);
    await page.getByText('message you and share your name').waitFor({
      state: 'detached',
    });
    assert.strictEqual(
      await page.getByText('message you and share your name').count(),
      0
    );
  });

  it('syncs message request state', async () => {
    const { phone, desktop } = bootstrap;

    debug('sending regular text message');
    await unknownContact.sendText(desktop, 'hello');

    debug('opening conversation');
    const leftPane = page.locator('#LeftPane');

    const conversationListItem = leftPane.getByRole('button', {
      name: 'Chat with Unknown contact',
    });
    await conversationListItem.getByText('Message Request').click();

    debug('sending message request sync');
    await phone.sendRaw(desktop, {
      content: {
        syncMessage: {
          content: {
            messageRequestResponse: {
              type: Proto.SyncMessage.MessageRequestResponse.Type.ACCEPT,
              threadAciBinary: unknownContact.device.aciRawUuid,
              groupId: null,
              threadAci: null,
            },
          },
          read: null,
          stickerPackOperation: null,
          viewed: null,
          padding: null,
        },
      },
      pniSignatureMessage: null,
      senderKeyDistributionMessage: null,
    });

    debug('verifying that compose is now visible');
    const composeArea = page.locator(
      '.composition-area-wrapper, .Inbox__conversation .ConversationView'
    );
    const input = composeArea.locator('[data-testid=CompositionInput]');
    await input.waitFor();
  });
});
