import { test } from 'node:test';
import assert from 'node:assert/strict';
import { sortBookmarks, groupBookmarksByRoom, isBookmarkSort } from './bookmarks';
import { Bookmark } from '../hooks/useBookmarks';

const bk = (eventId: string, roomId: string, savedAt: number, roomName = roomId): Bookmark => ({
  eventId,
  roomId,
  savedAt,
  roomName,
  previewText: eventId,
});

test('sortBookmarks newest orders by savedAt descending', () => {
  const input = [bk('a', 'r1', 100), bk('b', 'r1', 300), bk('c', 'r1', 200)];
  const out = sortBookmarks(input, 'newest');
  assert.deepEqual(
    out.map((b) => b.eventId),
    ['b', 'c', 'a'],
  );
});

test('sortBookmarks oldest orders by savedAt ascending', () => {
  const input = [bk('a', 'r1', 100), bk('b', 'r1', 300), bk('c', 'r1', 200)];
  const out = sortBookmarks(input, 'oldest');
  assert.deepEqual(
    out.map((b) => b.eventId),
    ['a', 'c', 'b'],
  );
});

test('sortBookmarks room falls back to newest for a flat list', () => {
  const input = [bk('a', 'r1', 100), bk('b', 'r2', 300)];
  const out = sortBookmarks(input, 'room');
  assert.deepEqual(
    out.map((b) => b.eventId),
    ['b', 'a'],
  );
});

test('sortBookmarks breaks savedAt ties deterministically by eventId', () => {
  const input = [bk('z', 'r1', 100), bk('a', 'r1', 100), bk('m', 'r1', 100)];
  const newest = sortBookmarks(input, 'newest');
  const oldest = sortBookmarks(input, 'oldest');
  // Equal timestamps → ascending eventId in both directions.
  assert.deepEqual(
    newest.map((b) => b.eventId),
    ['a', 'm', 'z'],
  );
  assert.deepEqual(
    oldest.map((b) => b.eventId),
    ['a', 'm', 'z'],
  );
});

test('sortBookmarks does not mutate its input', () => {
  const input = [bk('a', 'r1', 100), bk('b', 'r1', 300)];
  const before = input.map((b) => b.eventId);
  sortBookmarks(input, 'oldest');
  assert.deepEqual(
    input.map((b) => b.eventId),
    before,
  );
});

test('groupBookmarksByRoom buckets by room, newest-first within a group', () => {
  const input = [bk('a', 'r1', 100), bk('b', 'r2', 500), bk('c', 'r1', 300), bk('d', 'r2', 200)];
  const groups = groupBookmarksByRoom(input);
  assert.equal(groups.length, 2);
  const r1 = groups.find((g) => g.roomId === 'r1')!;
  const r2 = groups.find((g) => g.roomId === 'r2')!;
  assert.deepEqual(
    r1.items.map((b) => b.eventId),
    ['c', 'a'],
  );
  assert.deepEqual(
    r2.items.map((b) => b.eventId),
    ['b', 'd'],
  );
});

test('groupBookmarksByRoom orders groups by most-recent save (active rooms first)', () => {
  const input = [bk('a', 'r1', 100), bk('c', 'r1', 300), bk('b', 'r2', 500)];
  // r2's newest is 500, r1's newest is 300 → r2 first.
  const groups = groupBookmarksByRoom(input);
  assert.deepEqual(
    groups.map((g) => g.roomId),
    ['r2', 'r1'],
  );
});

test('groupBookmarksByRoom carries the stored room name', () => {
  const groups = groupBookmarksByRoom([bk('a', 'r1', 100, 'General')]);
  assert.equal(groups[0].roomName, 'General');
});

test('groupBookmarksByRoom orders equal-newest groups deterministically by roomId', () => {
  // Both rooms' newest save is 200 → tie broken by roomId ascending.
  const input = [bk('a', 'rB', 200), bk('b', 'rA', 200), bk('c', 'rA', 100)];
  const groups = groupBookmarksByRoom(input);
  assert.deepEqual(
    groups.map((g) => g.roomId),
    ['rA', 'rB'],
  );
});

test('groupBookmarksByRoom does not mutate its input', () => {
  const input = [bk('a', 'r1', 100), bk('b', 'r2', 300), bk('c', 'r1', 200)];
  const before = input.map((b) => b.eventId);
  groupBookmarksByRoom(input);
  assert.deepEqual(
    input.map((b) => b.eventId),
    before,
  );
});

test('groupBookmarksByRoom returns empty for empty input', () => {
  assert.deepEqual(groupBookmarksByRoom([]), []);
});

test('isBookmarkSort accepts valid values and rejects everything else', () => {
  assert.equal(isBookmarkSort('newest'), true);
  assert.equal(isBookmarkSort('oldest'), true);
  assert.equal(isBookmarkSort('room'), true);
  assert.equal(isBookmarkSort('bogus'), false);
  assert.equal(isBookmarkSort(''), false);
  assert.equal(isBookmarkSort(undefined), false);
  assert.equal(isBookmarkSort(null), false);
  assert.equal(isBookmarkSort(3), false);
});
