/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
import { ExtensionRegistryClient, } from './extensionRegistryClient.js';
import { fetchWithTimeout } from '@google/gemini-cli-core';
vi.mock('@google/gemini-cli-core', () => ({
    fetchWithTimeout: vi.fn(),
}));
const mockExtensions = [
    {
        id: 'ext1',
        rank: 1,
        url: 'https://github.com/test/ext1',
        fullName: 'test/ext1',
        repoDescription: 'Test extension 1',
        stars: 100,
        lastUpdated: '2025-01-01T00:00:00Z',
        extensionName: 'extension-one',
        extensionVersion: '1.0.0',
        extensionDescription: 'First test extension',
        avatarUrl: 'https://example.com/avatar1.png',
        hasMCP: true,
        hasContext: false,
        isGoogleOwned: false,
        licenseKey: 'mit',
        hasHooks: false,
        hasCustomCommands: false,
        hasSkills: false,
    },
    {
        id: 'ext2',
        rank: 2,
        url: 'https://github.com/test/ext2',
        fullName: 'test/ext2',
        repoDescription: 'Test extension 2',
        stars: 50,
        lastUpdated: '2025-01-02T00:00:00Z',
        extensionName: 'extension-two',
        extensionVersion: '0.5.0',
        extensionDescription: 'Second test extension',
        avatarUrl: 'https://example.com/avatar2.png',
        hasMCP: false,
        hasContext: true,
        isGoogleOwned: true,
        licenseKey: 'apache-2.0',
        hasHooks: false,
        hasCustomCommands: false,
        hasSkills: false,
    },
    {
        id: 'ext3',
        rank: 3,
        url: 'https://github.com/test/ext3',
        fullName: 'test/ext3',
        repoDescription: 'Test extension 3',
        stars: 10,
        lastUpdated: '2025-01-03T00:00:00Z',
        extensionName: 'extension-three',
        extensionVersion: '0.1.0',
        extensionDescription: 'Third test extension',
        avatarUrl: 'https://example.com/avatar3.png',
        hasMCP: true,
        hasContext: true,
        isGoogleOwned: false,
        licenseKey: 'gpl-3.0',
        hasHooks: false,
        hasCustomCommands: false,
        hasSkills: false,
    },
];
describe('ExtensionRegistryClient', () => {
    let client;
    let fetchMock;
    beforeEach(() => {
        ExtensionRegistryClient.resetCache();
        client = new ExtensionRegistryClient();
        fetchMock = fetchWithTimeout;
        fetchMock.mockReset();
    });
    afterEach(() => {
        vi.restoreAllMocks();
    });
    it('should fetch and return extensions with pagination (default ranking)', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const result = await client.getExtensions(1, 2);
        expect(result.extensions).toHaveLength(2);
        expect(result.extensions[0].id).toBe('ext1'); // rank 1
        expect(result.extensions[1].id).toBe('ext2'); // rank 2
        expect(result.total).toBe(3);
        expect(fetchMock).toHaveBeenCalledTimes(1);
        expect(fetchMock).toHaveBeenCalledWith('https://geminicli.com/extensions.json', 10000);
    });
    it('should return extensions sorted alphabetically', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const result = await client.getExtensions(1, 3, 'alphabetical');
        expect(result.extensions).toHaveLength(3);
        expect(result.extensions[0].id).toBe('ext1');
        expect(result.extensions[1].id).toBe('ext3');
        expect(result.extensions[2].id).toBe('ext2');
    });
    it('should return the second page of extensions', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const result = await client.getExtensions(2, 2);
        expect(result.extensions).toHaveLength(1);
        expect(result.extensions[0].id).toBe('ext3');
        expect(result.total).toBe(3);
    });
    it('should search extensions by name', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const results = await client.searchExtensions('one');
        expect(results.length).toBeGreaterThanOrEqual(1);
        expect(results[0].id).toBe('ext1');
    });
    it('should search extensions by description', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const results = await client.searchExtensions('Second');
        expect(results.length).toBeGreaterThanOrEqual(1);
        expect(results[0].id).toBe('ext2');
    });
    it('should get an extension by ID', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const result = await client.getExtension('ext2');
        expect(result).toBeDefined();
        expect(result?.id).toBe('ext2');
    });
    it('should return undefined if extension not found', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const result = await client.getExtension('non-existent');
        expect(result).toBeUndefined();
    });
    it('should cache the fetch result', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        await client.getExtensions();
        await client.getExtensions();
        expect(fetchMock).toHaveBeenCalledTimes(1);
    });
    it('should share the fetch result across instances', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => mockExtensions,
        });
        const client1 = new ExtensionRegistryClient();
        const client2 = new ExtensionRegistryClient();
        await client1.getExtensions();
        await client2.getExtensions();
        expect(fetchMock).toHaveBeenCalledTimes(1);
    });
    it('should throw an error if fetch fails', async () => {
        fetchMock.mockResolvedValue({
            ok: false,
            statusText: 'Not Found',
        });
        await expect(client.getExtensions()).rejects.toThrow('Failed to fetch extensions: Not Found');
    });
    it('should not return irrelevant results', async () => {
        fetchMock.mockResolvedValue({
            ok: true,
            json: async () => [
                ...mockExtensions,
                {
                    id: 'dataplex',
                    extensionName: 'dataplex',
                    extensionDescription: 'Connect to Dataplex Universal Catalog...',
                    fullName: 'google-cloud/dataplex',
                    rank: 6,
                    stars: 6,
                    url: '',
                    repoDescription: '',
                    lastUpdated: '',
                    extensionVersion: '1.0.0',
                    avatarUrl: '',
                    hasMCP: false,
                    hasContext: false,
                    isGoogleOwned: true,
                    licenseKey: '',
                    hasHooks: false,
                    hasCustomCommands: false,
                    hasSkills: false,
                },
                {
                    id: 'conductor',
                    extensionName: 'conductor',
                    extensionDescription: 'A conductor extension that actually matches.',
                    fullName: 'someone/conductor',
                    rank: 100,
                    stars: 100,
                    url: '',
                    repoDescription: '',
                    lastUpdated: '',
                    extensionVersion: '1.0.0',
                    avatarUrl: '',
                    hasMCP: false,
                    hasContext: false,
                    isGoogleOwned: false,
                    licenseKey: '',
                    hasHooks: false,
                    hasCustomCommands: false,
                    hasSkills: false,
                },
            ],
        });
        const results = await client.searchExtensions('conductor');
        const ids = results.map((r) => r.id);
        expect(ids).not.toContain('dataplex');
        expect(ids).toContain('conductor');
    });
});
//# sourceMappingURL=extensionRegistryClient.test.js.map