import { test } from 'node:test';
import assert from 'node:assert/strict';
import { MatrixEvent } from 'matrix-js-sdk';
import { packAddressEqual, imageUsageEqual, packMetaEqual, makeImagePacks } from './utils';
import { PackAddress } from './PackAddress';
import { PackMetaReader } from './PackMetaReader';
import { ImageUsage, PackContent, PackMeta } from './types';

test('packAddressEqual handles undefined and value equality', () => {
  assert.equal(packAddressEqual(undefined, undefined), true);
  assert.equal(packAddressEqual(new PackAddress('!r', 'k'), undefined), false);
  assert.equal(packAddressEqual(undefined, new PackAddress('!r', 'k')), false);
  assert.equal(packAddressEqual(new PackAddress('!r', 'k'), new PackAddress('!r', 'k')), true);
  assert.equal(packAddressEqual(new PackAddress('!r', 'k'), new PackAddress('!r', 'j')), false);
  assert.equal(packAddressEqual(new PackAddress('!r', 'k'), new PackAddress('!s', 'k')), false);
});

test('imageUsageEqual compares set membership and length', () => {
  assert.equal(imageUsageEqual([], []), true);
  assert.equal(imageUsageEqual([ImageUsage.Emoticon], [ImageUsage.Emoticon]), true);
  assert.equal(
    imageUsageEqual(
      [ImageUsage.Emoticon, ImageUsage.Sticker],
      [ImageUsage.Sticker, ImageUsage.Emoticon],
    ),
    true,
  );
  assert.equal(imageUsageEqual([ImageUsage.Emoticon], [ImageUsage.Sticker]), false);
  assert.equal(
    imageUsageEqual([ImageUsage.Emoticon], [ImageUsage.Emoticon, ImageUsage.Sticker]),
    false,
  );
});

const meta = (m: PackMeta) => new PackMetaReader(m);

test('packMetaEqual compares name, avatar, attribution and usage', () => {
  assert.equal(packMetaEqual(meta({ display_name: 'A' }), meta({ display_name: 'A' })), true);
  assert.equal(packMetaEqual(meta({ display_name: 'A' }), meta({ display_name: 'B' })), false);
  assert.equal(packMetaEqual(meta({ avatar_url: 'u' }), meta({ avatar_url: 'v' })), false);
  assert.equal(packMetaEqual(meta({ attribution: 'x' }), meta({ attribution: 'y' })), false);
  // both fall back to default usage => equal
  assert.equal(packMetaEqual(meta({}), meta({})), true);
  assert.equal(
    packMetaEqual(meta({ usage: [ImageUsage.Emoticon] }), meta({ usage: [ImageUsage.Sticker] })),
    false,
  );
});

const eventStub = (id: string | undefined, content: PackContent = {}): MatrixEvent =>
  ({
    getId: () => id,
    getRoomId: () => '!room:server',
    getStateKey: () => 'state-key',
    getContent: () => content,
  }) as unknown as MatrixEvent;

test('makeImagePacks builds packs and skips events without an id', () => {
  const events = [
    eventStub('$1', { pack: { display_name: 'One' } }),
    eventStub(undefined, { pack: { display_name: 'Skip' } }),
    eventStub('$2', { images: { cat: { url: 'mxc://x/cat' } } }),
  ];
  const packs = makeImagePacks(events);

  assert.equal(packs.length, 2);
  assert.equal(packs[0].id, '$1');
  assert.equal(packs[0].meta.name, 'One');
  assert.equal(packs[0].address?.roomId, '!room:server');
  assert.equal(packs[0].address?.stateKey, 'state-key');
  assert.equal(packs[1].id, '$2');
  assert.equal(packs[1].images.collection.get('cat')?.url, 'mxc://x/cat');
});

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