import { test } from 'node:test';
import assert from 'node:assert/strict';
import { ReceiptType } from 'matrix-js-sdk';
import { markThreadAsRead } from './threadReceipt';

// The regression this guards: sending a receipt for the thread ROOT (when
// replies aren't loaded, lastReply() is null / equals the root) becomes a MAIN
// receipt at an old event and drags the room's read marker backwards. It must
// only ever receipt a genuine loaded reply.

const evt = (id: string, sending = false) => ({ getId: () => id, isSending: () => sending }) as any;

const setup = (lastReply: any) => {
  const calls: Array<{ eventId: string; type: ReceiptType }> = [];
  const thread = { id: '$root', lastReply: () => lastReply } as any;
  const mx = {
    sendReadReceipt: async (e: any, type: ReceiptType) => {
      calls.push({ eventId: e.getId(), type });
      return {};
    },
  } as any;
  return { mx, thread, calls };
};

test('REGRESSION: no loaded reply (lastReply null) → NO receipt (never the root)', async () => {
  const { mx, thread, calls } = setup(null);
  await markThreadAsRead(mx, thread, false);
  assert.equal(calls.length, 0);
});

test('REGRESSION: lastReply IS the root → NO receipt', async () => {
  const { mx, thread, calls } = setup(evt('$root'));
  await markThreadAsRead(mx, thread, false);
  assert.equal(calls.length, 0);
});

test('genuine loaded reply → threaded receipt at that reply', async () => {
  const { mx, thread, calls } = setup(evt('$reply'));
  await markThreadAsRead(mx, thread, false);
  assert.equal(calls.length, 1);
  assert.equal(calls[0].eventId, '$reply');
  assert.equal(calls[0].type, ReceiptType.Read);
});

test('sending reply is skipped', async () => {
  const { mx, thread, calls } = setup(evt('$reply', true));
  await markThreadAsRead(mx, thread, false);
  assert.equal(calls.length, 0);
});

test('private flag uses ReadPrivate', async () => {
  const { mx, thread, calls } = setup(evt('$reply'));
  await markThreadAsRead(mx, thread, true);
  assert.equal(calls[0].type, ReceiptType.ReadPrivate);
});
