/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, expect, it } from 'vitest';
import { MockAgentProtocol } from './mock.js';
const waitForStreamEnd = (session) => new Promise((resolve) => {
    const events = [];
    const unsubscribe = session.subscribe((e) => {
        events.push(e);
        if (e.type === 'agent_end') {
            unsubscribe();
            resolve(events);
        }
    });
});
describe('MockAgentProtocol', () => {
    it('should emit queued events on send and subscribe', async () => {
        const session = new MockAgentProtocol();
        const event1 = {
            type: 'message',
            role: 'agent',
            content: [{ type: 'text', text: 'hello' }],
        };
        session.pushResponse([event1]);
        const streamPromise = waitForStreamEnd(session);
        const { streamId } = await session.send({
            message: [{ type: 'text', text: 'hi' }],
        });
        expect(streamId).toBeDefined();
        const streamedEvents = await streamPromise;
        // Ordered: user message, agent_start, agent message, agent_end = 4 events
        expect(streamedEvents).toHaveLength(4);
        expect(streamedEvents[0].type).toBe('message');
        expect(streamedEvents[0].role).toBe('user');
        expect(streamedEvents[1].type).toBe('agent_start');
        expect(streamedEvents[2].type).toBe('message');
        expect(streamedEvents[2].role).toBe('agent');
        expect(streamedEvents[3].type).toBe('agent_end');
        expect(session.events).toHaveLength(4);
        expect(session.events).toEqual(streamedEvents);
    });
    it('should handle multiple responses', async () => {
        const session = new MockAgentProtocol();
        // Test with empty payload (no message injected)
        session.pushResponse([]);
        session.pushResponse([
            {
                type: 'error',
                message: 'fail',
                fatal: true,
                status: 'RESOURCE_EXHAUSTED',
            },
        ]);
        // First send
        const stream1Promise = waitForStreamEnd(session);
        const { streamId: s1 } = await session.send({
            update: { title: 't1' },
        });
        const events1 = await stream1Promise;
        expect(events1).toHaveLength(3); // session_update, agent_start, agent_end
        expect(events1[0].type).toBe('session_update');
        expect(events1[1].type).toBe('agent_start');
        expect(events1[2].type).toBe('agent_end');
        // Second send
        const stream2Promise = waitForStreamEnd(session);
        const { streamId: s2 } = await session.send({
            update: { title: 't2' },
        });
        expect(s1).not.toBe(s2);
        const events2 = await stream2Promise;
        expect(events2).toHaveLength(4); // session_update, agent_start, error, agent_end
        expect(events2[0].type).toBe('session_update');
        expect(events2[1].type).toBe('agent_start');
        expect(events2[2].type).toBe('error');
        expect(events2[3].type).toBe('agent_end');
        expect(session.events).toHaveLength(7);
    });
    it('should handle abort on a waiting stream', async () => {
        const session = new MockAgentProtocol();
        // Use keepOpen to prevent auto agent_end
        session.pushResponse([{ type: 'message' }], { keepOpen: true });
        const events = [];
        let resolveStream;
        const streamPromise = new Promise((res) => {
            resolveStream = res;
        });
        session.subscribe((e) => {
            events.push(e);
            if (e.type === 'agent_end') {
                resolveStream(events);
            }
        });
        const { streamId: _streamId } = await session.send({
            update: { title: 't' },
        });
        // Initial events should have been emitted
        expect(events.map((e) => e.type)).toEqual([
            'session_update',
            'agent_start',
            'message',
        ]);
        // At this point, the stream should be "waiting" for more events because it's still active
        // and hasn't seen an agent_end.
        await session.abort();
        const finalEvents = await streamPromise;
        expect(finalEvents[3].type).toBe('agent_end');
        expect(finalEvents[3].reason).toBe('aborted');
    });
    it('should handle pushToStream on a waiting stream', async () => {
        const session = new MockAgentProtocol();
        session.pushResponse([], { keepOpen: true });
        const events = [];
        session.subscribe((e) => events.push(e));
        const { streamId } = await session.send({ update: { title: 't' } });
        expect(events.map((e) => e.type)).toEqual([
            'session_update',
            'agent_start',
        ]);
        // Push new event to active stream
        session.pushToStream(streamId, [{ type: 'message' }]);
        expect(events).toHaveLength(3);
        expect(events[2].type).toBe('message');
        await session.abort();
        expect(events).toHaveLength(4);
        expect(events[3].type).toBe('agent_end');
    });
    it('should handle pushToStream with close option', async () => {
        const session = new MockAgentProtocol();
        session.pushResponse([], { keepOpen: true });
        const streamPromise = waitForStreamEnd(session);
        const { streamId } = await session.send({ update: { title: 't' } });
        // Push new event and close
        session.pushToStream(streamId, [{ type: 'message' }], { close: true });
        const events = await streamPromise;
        expect(events.map((e) => e.type)).toEqual([
            'session_update',
            'agent_start',
            'message',
            'agent_end',
        ]);
        expect(events[3].reason).toBe('completed');
    });
    it('should not double up on agent_end if provided manually', async () => {
        const session = new MockAgentProtocol();
        session.pushResponse([
            { type: 'message' },
            { type: 'agent_end', reason: 'completed' },
        ]);
        const streamPromise = waitForStreamEnd(session);
        await session.send({ update: { title: 't' } });
        const events = await streamPromise;
        const endEvents = events.filter((e) => e.type === 'agent_end');
        expect(endEvents).toHaveLength(1);
    });
    it('should handle elicitations', async () => {
        const session = new MockAgentProtocol();
        session.pushResponse([]);
        const streamPromise = waitForStreamEnd(session);
        await session.send({
            elicitations: [
                { requestId: 'r1', action: 'accept', content: { foo: 'bar' } },
            ],
        });
        const events = await streamPromise;
        expect(events[0].type).toBe('elicitation_response');
        expect(events[0].requestId).toBe('r1');
        expect(events[1].type).toBe('agent_start');
    });
    it('should handle updates and track state', async () => {
        const session = new MockAgentProtocol();
        session.pushResponse([]);
        const streamPromise = waitForStreamEnd(session);
        await session.send({
            update: { title: 'New Title', model: 'gpt-4', config: { x: 1 } },
        });
        expect(session.title).toBe('New Title');
        expect(session.model).toBe('gpt-4');
        expect(session.config).toEqual({ x: 1 });
        const events = await streamPromise;
        expect(events[0].type).toBe('session_update');
        expect(events[1].type).toBe('agent_start');
    });
    it('should return streamId: null if no response queued', async () => {
        const session = new MockAgentProtocol();
        const { streamId } = await session.send({ update: { title: 'foo' } });
        expect(streamId).toBeNull();
        expect(session.events).toHaveLength(1);
        expect(session.events[0].type).toBe('session_update');
        expect(session.events[0].streamId).toEqual(expect.any(String));
    });
    it('should throw on action', async () => {
        const session = new MockAgentProtocol();
        await expect(session.send({ action: { type: 'foo', data: {} } })).rejects.toThrow('Actions not supported in MockAgentProtocol: foo');
    });
});
//# sourceMappingURL=mock.test.js.map