import assert from 'node:assert/strict';
import { test } from 'node:test';
import { contextWithProfiles, roomsLackingProfiles, withProfiles } from '../src/lib/mention-profiles.ts';
import type { MemberSummary, Sender, TimelineItem } from '../src/lib/types.ts';

const bare = (user_id: string): Sender => ({ user_id, display_name: null, avatar: null, name_ambiguous: false });

function message(sender: Sender, replySender: Sender | null = null): TimelineItem {
  return {
    kind: 'event',
    event: {
      item_id: `i-${sender.user_id}`,
      event_id: `$e-${sender.user_id}`,
      transaction_id: null,
      sender,
      timestamp_ms: 1,
      own: false,
      send_state: { kind: 'Sent' },
      content: { kind: 'Redacted' },
      reply_to: replySender ? { event_id: '$target', details: { kind: 'Ready', sender: replySender, content: { kind: 'Redacted' }, timestamp_ms: 0 } } : null,
      thread_root: null,
      thread_summary: null,
      reactions: [],
      read_by: [],
      editable: false
    }
  };
}

function member(user_id: string, display_name: string | null, avatar: string | null = null): MemberSummary {
  return { user_id, name: display_name ?? user_id, display_name, avatar, membership: 'Join', own: false, name_ambiguous: false, ignored: false, service: false };
}

const members = { '@carol:x': member('@carol:x', 'Carol', 'mxc://x/c'), '@dave:x': member('@dave:x', 'Dave') };

test('lists only rooms with a sender or reply sender missing both name and avatar', () => {
  const named = { ...bare('@carol:x'), display_name: 'Carol' };
  const rooms = roomsLackingProfiles([
    { roomId: '!a:x', item: message(named) },
    { roomId: '!b:x', item: message(bare('@carol:x')) },
    { roomId: '!c:x', item: message(named, bare('@dave:x')) },
    { roomId: '!d:x', item: { kind: 'readMarker' } }
  ]);
  assert.deepEqual([...rooms].sort(), ['!b:x', '!c:x']);
});

test('fills the sender and reply sender from the room members', () => {
  const filled = withProfiles(message(bare('@carol:x'), bare('@dave:x')), members);
  assert.equal(filled.kind, 'event');
  if (filled.kind !== 'event') return;
  assert.equal(filled.event.sender.display_name, 'Carol');
  assert.equal(filled.event.sender.avatar, 'mxc://x/c');
  assert.equal(filled.event.reply_to?.details.kind === 'Ready' && filled.event.reply_to.details.sender.display_name, 'Dave');
});

test('keeps an engine profile and the same item when nothing changes', () => {
  const named = message({ ...bare('@carol:x'), display_name: 'Carol from the engine' });
  assert.equal(withProfiles(named, members), named);
  const unknown = message(bare('@erin:x'));
  assert.equal(withProfiles(unknown, members), unknown);
  const context = { events_before: [unknown], event: named, events_after: [], start_token: null, end_token: null };
  assert.equal(contextWithProfiles(context, undefined), context);
});
