import { describe, it, expect } from 'vitest';
import { MessageSocket } from './message-socket';
import type { SocketLike } from './types';

class FakeSocket implements SocketLike {
  handlers = new Map<string, Array<(...a: unknown[]) => void>>();
  acks: Array<{ event: string; payload: unknown }> = [];
  ackReturn: unknown = { threadId: 't5', status: 'OPEN', history: [] };

  on(event: string, handler: (...a: unknown[]) => void): unknown {
    const list = this.handlers.get(event) ?? [];
    list.push(handler);
    this.handlers.set(event, list);
    return this;
  }
  off(): unknown {
    return this;
  }
  emit(): unknown {
    return this;
  }
  async emitWithAck(event: string, ...args: unknown[]): Promise<unknown> {
    this.acks.push({ event, payload: args[0] });
    return this.ackReturn;
  }
  connect(): unknown {
    return this;
  }
  disconnect(): unknown {
    return this;
  }
  trigger(event: string, ...args: unknown[]): void {
    (this.handlers.get(event) ?? []).forEach((h) => h(...args));
  }
}

describe('MessageSocket reconnect resilience', () => {
  it('re-opens the active thread when the socket reconnects (no lost subscription)', async () => {
    const fake = new FakeSocket();
    const ms = new MessageSocket({ serviceUrl: 'http://localhost:3200', token: 'tok' }, fake);

    await ms.openThread('t5');
    const before = fake.acks.filter((a) => a.event === 'open_thread').length;

    fake.trigger('connect'); // simulate a reconnect

    const opens = fake.acks.filter((a) => a.event === 'open_thread');
    expect(opens.length).toBe(before + 1);
    expect(opens.at(-1)?.payload).toMatchObject({ threadId: 't5' });
  });
});
