"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const index_js_1 = require("./index.js");
// --- Mocks ---
const mockGetMe = vitest_1.vi.fn();
const mockSetWebhook = vitest_1.vi.fn();
const mockDeleteWebhook = vitest_1.vi.fn();
vitest_1.vi.mock('./bot-client.js', () => ({
    TelegramBotClient: vitest_1.vi.fn().mockImplementation(() => ({
        getMe: mockGetMe,
        setWebhook: mockSetWebhook,
        deleteWebhook: mockDeleteWebhook,
    })),
}));
vitest_1.vi.mock('./webhook-handler.js', () => ({
    WebhookHandler: vitest_1.vi.fn().mockImplementation(() => ({
        registerToken: vitest_1.vi.fn(),
        unregisterToken: vitest_1.vi.fn(),
    })),
}));
vitest_1.vi.mock('./channel-manager.js', () => ({
    ChannelManager: vitest_1.vi.fn().mockImplementation(() => ({
        stopSchedule: vitest_1.vi.fn(),
        stopAllSchedules: vitest_1.vi.fn(),
    })),
}));
vitest_1.vi.mock('./stars-manager.js', () => ({
    StarsManager: vitest_1.vi.fn().mockImplementation(() => ({})),
}));
vitest_1.vi.mock('../../utils/index.js', () => ({
    createModuleLogger: () => ({
        debug: vitest_1.vi.fn(),
        info: vitest_1.vi.fn(),
        warn: vitest_1.vi.fn(),
        error: vitest_1.vi.fn(),
    }),
}));
const BOT_INFO = {
    id: 111222333,
    is_bot: true,
    first_name: 'TestBot',
    username: 'test_bot',
};
function createMockDataStore() {
    return {
        saveCharacterChannelConfig: vitest_1.vi.fn(),
        getCharacterChannelConfig: vitest_1.vi.fn(),
    };
}
function createMockEncryptedStore() {
    const store = new Map();
    return {
        setKey: vitest_1.vi.fn(async (name, value) => { store.set(name, value); }),
        getKey: vitest_1.vi.fn(async (name) => store.get(name) ?? null),
        deleteKey: vitest_1.vi.fn(async (name) => { const had = store.has(name); store.delete(name); return had; }),
        listKeys: vitest_1.vi.fn(async () => Array.from(store.entries()).map(([name]) => ({
            name,
            maskedValue: '****',
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
        }))),
        hasKey: vitest_1.vi.fn(async (name) => store.has(name)),
        _store: store,
    };
}
(0, vitest_1.describe)('TelegramManager', () => {
    let manager;
    let dataStore;
    let encryptedStore;
    (0, vitest_1.beforeEach)(() => {
        vitest_1.vi.clearAllMocks();
        mockGetMe.mockResolvedValue(BOT_INFO);
        mockSetWebhook.mockResolvedValue(true);
        mockDeleteWebhook.mockResolvedValue(true);
        dataStore = createMockDataStore();
        encryptedStore = createMockEncryptedStore();
        manager = new index_js_1.TelegramManager(dataStore, encryptedStore);
    });
    (0, vitest_1.describe)('addBot', () => {
        (0, vitest_1.it)('validates token via getMe and stores encrypted token', async () => {
            const result = await manager.addBot('char-1', 'token-abc');
            (0, vitest_1.expect)(result).toEqual(BOT_INFO);
            (0, vitest_1.expect)(mockGetMe).toHaveBeenCalledOnce();
            (0, vitest_1.expect)(encryptedStore.setKey).toHaveBeenCalledWith('bot-token:char-1', 'token-abc');
        });
        (0, vitest_1.it)('registers token with webhook handler', async () => {
            await manager.addBot('char-1', 'token-abc');
            const handler = manager.getWebhookHandler();
            (0, vitest_1.expect)(handler.registerToken).toHaveBeenCalledWith('token-abc');
        });
        (0, vitest_1.it)('makes bot available via getBotClient', async () => {
            await manager.addBot('char-1', 'token-abc');
            const client = manager.getBotClient('char-1');
            (0, vitest_1.expect)(client).toBeDefined();
        });
        (0, vitest_1.it)('throws if getMe fails (invalid token)', async () => {
            mockGetMe.mockRejectedValueOnce(new Error('Unauthorized'));
            await (0, vitest_1.expect)(manager.addBot('char-1', 'bad-token')).rejects.toThrow('Unauthorized');
        });
    });
    (0, vitest_1.describe)('removeBot', () => {
        (0, vitest_1.it)('removes bot, deletes webhook, and cleans up encrypted token', async () => {
            await manager.addBot('char-1', 'token-abc');
            await manager.removeBot('char-1');
            (0, vitest_1.expect)(mockDeleteWebhook).toHaveBeenCalled();
            (0, vitest_1.expect)(encryptedStore.deleteKey).toHaveBeenCalledWith('bot-token:char-1');
            (0, vitest_1.expect)(manager.getBotClient('char-1')).toBeUndefined();
        });
        (0, vitest_1.it)('handles removal of non-existent bot gracefully', async () => {
            await (0, vitest_1.expect)(manager.removeBot('nonexistent')).resolves.toBeUndefined();
            (0, vitest_1.expect)(encryptedStore.deleteKey).toHaveBeenCalledWith('bot-token:nonexistent');
        });
        (0, vitest_1.it)('unregisters token from webhook handler', async () => {
            await manager.addBot('char-1', 'token-abc');
            await manager.removeBot('char-1');
            const handler = manager.getWebhookHandler();
            (0, vitest_1.expect)(handler.unregisterToken).toHaveBeenCalledWith('token-abc');
        });
    });
    (0, vitest_1.describe)('updateBot', () => {
        (0, vitest_1.it)('removes old bot and adds new one', async () => {
            await manager.addBot('char-1', 'old-token');
            const newBotInfo = { ...BOT_INFO, username: 'new_bot' };
            mockGetMe.mockResolvedValueOnce(newBotInfo);
            const result = await manager.updateBot('char-1', 'new-token');
            (0, vitest_1.expect)(result).toEqual(newBotInfo);
            (0, vitest_1.expect)(encryptedStore.deleteKey).toHaveBeenCalledWith('bot-token:char-1');
            (0, vitest_1.expect)(encryptedStore.setKey).toHaveBeenCalledWith('bot-token:char-1', 'new-token');
        });
    });
    (0, vitest_1.describe)('validateBot', () => {
        (0, vitest_1.it)('validates existing bot and updates botInfo', async () => {
            await manager.addBot('char-1', 'token-abc');
            const updatedInfo = { ...BOT_INFO, first_name: 'UpdatedBot' };
            mockGetMe.mockResolvedValueOnce(updatedInfo);
            const result = await manager.validateBot('char-1');
            (0, vitest_1.expect)(result).toEqual(updatedInfo);
        });
        (0, vitest_1.it)('throws for non-existent bot', async () => {
            await (0, vitest_1.expect)(manager.validateBot('nonexistent')).rejects.toThrow('No bot found');
        });
    });
    (0, vitest_1.describe)('getBotClient', () => {
        (0, vitest_1.it)('returns undefined for unknown character', () => {
            (0, vitest_1.expect)(manager.getBotClient('unknown')).toBeUndefined();
        });
        (0, vitest_1.it)('returns client for added bot', async () => {
            await manager.addBot('char-1', 'token-abc');
            (0, vitest_1.expect)(manager.getBotClient('char-1')).toBeDefined();
        });
    });
    (0, vitest_1.describe)('setupWebhook', () => {
        (0, vitest_1.it)('sets webhook with correct URL', async () => {
            await manager.addBot('char-1', 'token-abc');
            await manager.setupWebhook('char-1', 'https://example.com');
            (0, vitest_1.expect)(mockSetWebhook).toHaveBeenCalledWith('https://example.com/api/v1/webhooks/telegram/token-abc');
        });
        (0, vitest_1.it)('throws for non-existent bot', async () => {
            await (0, vitest_1.expect)(manager.setupWebhook('nonexistent', 'https://example.com')).rejects.toThrow('No bot found');
        });
    });
    (0, vitest_1.describe)('removeWebhook', () => {
        (0, vitest_1.it)('deletes webhook for existing bot', async () => {
            await manager.addBot('char-1', 'token-abc');
            await manager.removeWebhook('char-1');
            (0, vitest_1.expect)(mockDeleteWebhook).toHaveBeenCalled();
        });
        (0, vitest_1.it)('throws for non-existent bot', async () => {
            await (0, vitest_1.expect)(manager.removeWebhook('nonexistent')).rejects.toThrow('No bot found');
        });
    });
    (0, vitest_1.describe)('getWebhookHandler', () => {
        (0, vitest_1.it)('returns the shared WebhookHandler instance', () => {
            const handler = manager.getWebhookHandler();
            (0, vitest_1.expect)(handler).toBeDefined();
            (0, vitest_1.expect)(manager.getWebhookHandler()).toBe(handler);
        });
    });
    (0, vitest_1.describe)('getChannelManager', () => {
        (0, vitest_1.it)('returns the shared ChannelManager instance', () => {
            const cm = manager.getChannelManager();
            (0, vitest_1.expect)(cm).toBeDefined();
            (0, vitest_1.expect)(manager.getChannelManager()).toBe(cm);
        });
    });
    (0, vitest_1.describe)('getStarsManager', () => {
        (0, vitest_1.it)('returns the shared StarsManager instance', () => {
            const sm = manager.getStarsManager();
            (0, vitest_1.expect)(sm).toBeDefined();
            (0, vitest_1.expect)(manager.getStarsManager()).toBe(sm);
        });
    });
    (0, vitest_1.describe)('start', () => {
        (0, vitest_1.it)('loads all stored bot tokens and creates clients', async () => {
            // Pre-populate encrypted store with bot tokens
            encryptedStore._store.set('bot-token:char-1', 'token-1');
            encryptedStore._store.set('bot-token:char-2', 'token-2');
            encryptedStore._store.set('openrouter-key', 'or-key'); // non-bot key
            await manager.start();
            (0, vitest_1.expect)(manager.getBotClient('char-1')).toBeDefined();
            (0, vitest_1.expect)(manager.getBotClient('char-2')).toBeDefined();
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(2);
        });
        (0, vitest_1.it)('continues loading other bots if one fails validation', async () => {
            encryptedStore._store.set('bot-token:char-ok', 'token-ok');
            encryptedStore._store.set('bot-token:char-bad', 'token-bad');
            let callCount = 0;
            mockGetMe.mockImplementation(() => {
                callCount++;
                if (callCount === 1)
                    return Promise.reject(new Error('Invalid token'));
                return Promise.resolve(BOT_INFO);
            });
            await manager.start();
            // At least one bot should be loaded
            (0, vitest_1.expect)(manager.getActiveBots().size).toBeGreaterThanOrEqual(1);
        });
        (0, vitest_1.it)('handles empty store gracefully', async () => {
            await manager.start();
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(0);
        });
    });
    (0, vitest_1.describe)('stop', () => {
        (0, vitest_1.it)('cleans up all bots and stops schedules', async () => {
            await manager.addBot('char-1', 'token-1');
            await manager.addBot('char-2', 'token-2');
            await manager.stop();
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(0);
            (0, vitest_1.expect)(mockDeleteWebhook).toHaveBeenCalled();
            (0, vitest_1.expect)(manager.getChannelManager().stopAllSchedules).toHaveBeenCalled();
        });
        (0, vitest_1.it)('handles webhook deletion failure gracefully during stop', async () => {
            await manager.addBot('char-1', 'token-1');
            mockDeleteWebhook.mockRejectedValueOnce(new Error('Network error'));
            await (0, vitest_1.expect)(manager.stop()).resolves.toBeUndefined();
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(0);
        });
    });
    (0, vitest_1.describe)('getActiveBots', () => {
        (0, vitest_1.it)('returns empty map when no bots', () => {
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(0);
        });
        (0, vitest_1.it)('returns all active bots with info', async () => {
            await manager.addBot('char-1', 'token-1');
            await manager.addBot('char-2', 'token-2');
            const bots = manager.getActiveBots();
            (0, vitest_1.expect)(bots.size).toBe(2);
            (0, vitest_1.expect)(bots.get('char-1')?.characterId).toBe('char-1');
            (0, vitest_1.expect)(bots.get('char-1')?.botInfo).toEqual(BOT_INFO);
            (0, vitest_1.expect)(bots.get('char-2')?.characterId).toBe('char-2');
        });
    });
    (0, vitest_1.describe)('getBotStatus', () => {
        (0, vitest_1.it)('returns active=false for unknown character', async () => {
            const status = await manager.getBotStatus('unknown');
            (0, vitest_1.expect)(status).toEqual({ active: false });
        });
        (0, vitest_1.it)('returns active=true with botInfo for added bot', async () => {
            await manager.addBot('char-1', 'token-abc');
            const status = await manager.getBotStatus('char-1');
            (0, vitest_1.expect)(status.active).toBe(true);
            (0, vitest_1.expect)(status.botInfo).toEqual(BOT_INFO);
        });
    });
    (0, vitest_1.describe)('multi-bot management', () => {
        (0, vitest_1.it)('manages multiple bots independently', async () => {
            const info1 = { ...BOT_INFO, id: 1, username: 'bot_1' };
            const info2 = { ...BOT_INFO, id: 2, username: 'bot_2' };
            mockGetMe.mockResolvedValueOnce(info1).mockResolvedValueOnce(info2);
            await manager.addBot('char-1', 'token-1');
            await manager.addBot('char-2', 'token-2');
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(2);
            await manager.removeBot('char-1');
            (0, vitest_1.expect)(manager.getActiveBots().size).toBe(1);
            (0, vitest_1.expect)(manager.getBotClient('char-1')).toBeUndefined();
            (0, vitest_1.expect)(manager.getBotClient('char-2')).toBeDefined();
        });
    });
});
//# sourceMappingURL=index.test.js.map