import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createStore } from 'jotai';
import { callEmbedAtom } from './callEmbed';
import { CallEmbed } from '../plugins/call';

// callEmbedAtom holds the current CallEmbed in an unexported baseAtom. The setter:
//   - identity no-op guard: setting the same reference does nothing
//   - when replacing a previous embed, calls prevCallEmbed.dispose()
// We substitute a stub embed exposing a dispose() spy (the real CallEmbed needs a
// MatrixClient + DOM). `as unknown as CallEmbed` keeps eslint/prettier quiet.

type StubEmbed = { dispose: () => void; disposed: number };

const makeEmbed = (): StubEmbed => {
  const stub: StubEmbed = {
    disposed: 0,
    dispose() {
      stub.disposed += 1;
    },
  };
  return stub;
};

const asEmbed = (e: StubEmbed): CallEmbed => e as unknown as CallEmbed;

test('starts undefined', () => {
  const store = createStore();
  assert.equal(store.get(callEmbedAtom), undefined);
});

test('sets a call embed', () => {
  const store = createStore();
  const embed = makeEmbed();
  store.set(callEmbedAtom, asEmbed(embed));
  assert.equal(store.get(callEmbedAtom), asEmbed(embed));
  assert.equal(embed.disposed, 0);
});

test('replacing an embed disposes the previous one', () => {
  const store = createStore();
  const first = makeEmbed();
  const second = makeEmbed();

  store.set(callEmbedAtom, asEmbed(first));
  store.set(callEmbedAtom, asEmbed(second));

  assert.equal(first.disposed, 1);
  assert.equal(second.disposed, 0);
  assert.equal(store.get(callEmbedAtom), asEmbed(second));
});

test('setting the same embed reference is a no-op (no dispose)', () => {
  const store = createStore();
  const embed = makeEmbed();

  store.set(callEmbedAtom, asEmbed(embed));
  store.set(callEmbedAtom, asEmbed(embed));

  assert.equal(embed.disposed, 0);
  assert.equal(store.get(callEmbedAtom), asEmbed(embed));
});

test('clearing to undefined disposes the previous embed', () => {
  const store = createStore();
  const embed = makeEmbed();

  store.set(callEmbedAtom, asEmbed(embed));
  store.set(callEmbedAtom, undefined);

  assert.equal(embed.disposed, 1);
  assert.equal(store.get(callEmbedAtom), undefined);
});

test('setting undefined when already undefined is a no-op', () => {
  const store = createStore();
  // No previous embed: the identity guard (undefined === undefined) returns early.
  store.set(callEmbedAtom, undefined);
  assert.equal(store.get(callEmbedAtom), undefined);
});
