import { describe, it, expect, beforeEach, vi } from 'vitest';
import Database from 'better-sqlite3';
import { ChatHandler } from '../chat-handler';
import { getActiveConversation, getMessages, } from '../conversation';
import { SCHEMA_SQL } from '../../db/schema';
function createTestDb() {
    const db = new Database(':memory:');
    db.pragma('journal_mode = WAL');
    db.exec(SCHEMA_SQL);
    return db;
}
describe('Chat round-trip integration', () => {
    let db;
    let broadcasts;
    let capturedBridgeCalls;
    let handler;
    beforeEach(() => {
        db = createTestDb();
        broadcasts = [];
        capturedBridgeCalls = [];
        const mockBridge = {
            type: 'claude-code',
            send: vi.fn((opts) => {
                capturedBridgeCalls.push(opts);
            }),
            isActive: vi.fn().mockReturnValue(false),
            kill: vi.fn(),
        };
        handler = new ChatHandler({
            db,
            bridge: mockBridge,
            broadcast: (squadName, message) => {
                broadcasts.push({ squadName, message });
            },
            squadsDir: '/tmp/squads',
            broadcastToAll: vi.fn(),
        });
    });
    it('should complete a full send -> stream -> done cycle', () => {
        handler.handleChatSend('content-team', 'What topics should we cover?');
        const createMsg = broadcasts.find((b) => b.message.type === 'chat:conversation_created');
        expect(createMsg).toBeDefined();
        expect(createMsg.squadName).toBe('content-team');
        const conv = getActiveConversation(db, 'content-team');
        expect(conv).not.toBeNull();
        const msgs1 = getMessages(db, conv.id, { limit: 50 });
        expect(msgs1.data).toHaveLength(1);
        expect(msgs1.data[0].role).toBe('user');
        expect(msgs1.data[0].content).toBe('What topics should we cover?');
        const bridgeCall = capturedBridgeCalls[0];
        expect(bridgeCall.squadName).toBe('content-team');
        expect(bridgeCall.prompt).toContain('What topics should we cover?');
        bridgeCall.onChunk('Here are ');
        bridgeCall.onChunk('5 topics');
        const chunks = broadcasts.filter((b) => b.message.type === 'chat:chunk');
        expect(chunks).toHaveLength(2);
        expect(chunks[0].message.delta).toBe('Here are ');
        expect(chunks[1].message.delta).toBe('5 topics');
        bridgeCall.onDone('Here are 5 topics');
        const msgs2 = getMessages(db, conv.id, { limit: 50 });
        expect(msgs2.data).toHaveLength(2);
        expect(msgs2.data[1].role).toBe('assistant');
        expect(msgs2.data[1].content).toBe('Here are 5 topics');
        const doneMsg = broadcasts.find((b) => b.message.type === 'chat:done');
        expect(doneMsg).toBeDefined();
        expect(doneMsg.message.messageId).toBeDefined();
    });
    it('should persist multiple messages in the same conversation', () => {
        handler.handleChatSend('content-team', 'Hello');
        capturedBridgeCalls[0].onDone('Hi!');
        handler.handleChatSend('content-team', 'Tell me more');
        capturedBridgeCalls[1].onDone('Sure, here is more info');
        const conv = getActiveConversation(db, 'content-team');
        const msgs = getMessages(db, conv.id, { limit: 50 });
        expect(msgs.data).toHaveLength(4);
        // Same-millisecond IDs may sort by random hex suffix, so verify content exists
        const contents = msgs.data.map((m) => m.content);
        expect(contents).toContain('Hello');
        expect(contents).toContain('Hi!');
        expect(contents).toContain('Tell me more');
        expect(contents).toContain('Sure, here is more info');
        // Verify roles: 2 user + 2 assistant
        expect(msgs.data.filter((m) => m.role === 'user')).toHaveLength(2);
        expect(msgs.data.filter((m) => m.role === 'assistant')).toHaveLength(2);
    });
    it('should include conversation history in bridge prompt', () => {
        handler.handleChatSend('content-team', 'Hello');
        capturedBridgeCalls[0].onDone('Hi there!');
        handler.handleChatSend('content-team', 'What next?');
        const secondPrompt = capturedBridgeCalls[1].prompt;
        expect(secondPrompt).toContain('User: Hello');
        expect(secondPrompt).toContain('Assistant: Hi there!');
        expect(secondPrompt).toContain('User: What next?');
    });
    it('should handle bridge error gracefully', () => {
        handler.handleChatSend('content-team', 'Hello');
        capturedBridgeCalls[0].onError({ code: 1, message: 'Process failed' });
        const errorMsg = broadcasts.find((b) => b.message.type === 'chat:error');
        expect(errorMsg).toBeDefined();
        expect(errorMsg.message.error).toBe('Process failed');
        const conv = getActiveConversation(db, 'content-team');
        const msgs = getMessages(db, conv.id, { limit: 50 });
        expect(msgs.data).toHaveLength(1);
        expect(msgs.data[0].role).toBe('user');
    });
    it('should create a fresh conversation on handleNewConversation', () => {
        // Insert old conversation with explicit earlier timestamp
        db.prepare('INSERT INTO conversations (id, squad_name, created_at) VALUES (?, ?, ?)').run('2026-03-13T09:00:00.000Z-old', 'content-team', '2026-03-13T09:00:00.000Z');
        db.prepare('INSERT INTO chat_messages (id, conversation_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)').run('2026-03-13T09:00:01.000Z-m1', '2026-03-13T09:00:00.000Z-old', 'user', 'Old message', '2026-03-13T09:00:01.000Z');
        // Create new conversation — its generateId() will produce a later timestamp than 2026-03-13T09:00:00
        handler.handleNewConversation('content-team');
        // handleChatSend should pick up the new (latest) conversation
        handler.handleChatSend('content-team', 'New message');
        capturedBridgeCalls[0].onDone('New response');
        // Verify the new conversation got the new messages
        const convCreatedBroadcasts = broadcasts.filter((b) => b.message.type === 'chat:conversation_created');
        expect(convCreatedBroadcasts).toHaveLength(1);
        // There should be 2 conversations total
        const allConvs = db.prepare('SELECT * FROM conversations WHERE squad_name = ?').all('content-team');
        expect(allConvs).toHaveLength(2);
        // The newest conversation should have only 2 messages (New message + New response)
        const newConvId = convCreatedBroadcasts[0].message.conversationId;
        const msgs = getMessages(db, newConvId, { limit: 50 });
        const contents = msgs.data.map((m) => m.content);
        expect(contents).toContain('New message');
        expect(contents).toContain('New response');
    });
});
//# sourceMappingURL=chat-integration.test.js.map