import { test } from 'node:test';
import assert from 'node:assert/strict';
import { filterGroupsByMsgType, filterGroupsByPinned, ResultGroup } from './useMessageSearch';

// Minimal ResultGroup/ResultItem fixtures — only the fields the filters read
// (event.content.msgtype, event.event_id, group.roomId).
const item = (msgtype: string | undefined, eventId: string) => ({
  rank: 1,
  event: { event_id: eventId, content: msgtype === undefined ? {} : { msgtype } },
  context: {},
});
const mkGroups = (
  ...groups: { roomId: string; items: ReturnType<typeof item>[] }[]
): ResultGroup[] => groups as unknown as ResultGroup[];

test('filterGroupsByMsgType: empty filter returns groups unchanged', () => {
  const groups = mkGroups({ roomId: '!r1', items: [item('m.text', '$1'), item('m.image', '$2')] });
  assert.equal(filterGroupsByMsgType(groups, []), groups);
});

test('filterGroupsByMsgType: keeps only matching msgtypes (union)', () => {
  const groups = mkGroups({
    roomId: '!r1',
    items: [item('m.text', '$1'), item('m.image', '$2'), item('m.file', '$3')],
  });
  const out = filterGroupsByMsgType(groups, ['m.image', 'm.file']);
  assert.equal(out.length, 1);
  assert.deepEqual(
    out[0].items.map((i) => i.event.event_id),
    ['$2', '$3'],
  );
});

test('filterGroupsByMsgType: drops groups left empty', () => {
  const groups = mkGroups(
    { roomId: '!r1', items: [item('m.text', '$1')] },
    { roomId: '!r2', items: [item('m.image', '$2')] },
  );
  const out = filterGroupsByMsgType(groups, ['m.image']);
  assert.equal(out.length, 1);
  assert.equal(out[0].roomId, '!r2');
});

test('filterGroupsByMsgType: ignores items with a non-string msgtype', () => {
  const groups = mkGroups({ roomId: '!r1', items: [item(undefined, '$1'), item('m.video', '$2')] });
  const out = filterGroupsByMsgType(groups, ['m.video']);
  assert.equal(out[0].items.length, 1);
  assert.equal(out[0].items[0].event.event_id, '$2');
});

test('filterGroupsByPinned: disabled returns groups unchanged', () => {
  const groups = mkGroups({ roomId: '!r1', items: [item('m.text', '$1')] });
  assert.equal(
    filterGroupsByPinned(groups, false, () => false),
    groups,
  );
});

test('filterGroupsByPinned: keeps pinned items and drops empty groups', () => {
  const groups = mkGroups(
    { roomId: '!r1', items: [item('m.text', '$1'), item('m.text', '$2')] },
    { roomId: '!r2', items: [item('m.text', '$3')] },
  );
  const pinned = new Set(['!r1/$2']);
  const out = filterGroupsByPinned(groups, true, (roomId, eventId) =>
    pinned.has(`${roomId}/${eventId}`),
  );
  assert.equal(out.length, 1);
  assert.equal(out[0].roomId, '!r1');
  assert.deepEqual(
    out[0].items.map((i) => i.event.event_id),
    ['$2'],
  );
});
