import { describe, it, expect } from 'vitest';
import assert from 'node:assert/strict';
function buildUnifiedToolConfig(template) {
    const normalizedBaseUrl = String(template.baseUrl || '').trim();
    const normalizedApiKey = String(template.apiKey || '').trim();
    const normalizedModels = [
        ...(Array.isArray(template.models) ? template.models : []),
        template.model,
    ]
        .map((item) => String(item || '').trim())
        .filter((item, index, list) => item && list.indexOf(item) === index);
    const normalizedModel = normalizedModels[0] || String(template.model || '').trim();
    const normalizedOpenCodeBaseUrl = normalizedBaseUrl.endsWith('/v1')
        ? normalizedBaseUrl
        : `${normalizedBaseUrl.replace(/\/+$/, '')}/v1`;
    const opencodeModels = Object.fromEntries(normalizedModels.map((model) => [model, {
            name: model,
            modalities: {
                input: ['text', 'image'],
                output: ['text'],
            },
        }]));
    return {
        claudecode: {
            env: {
                ANTHROPIC_BASE_URL: normalizedBaseUrl,
                ANTHROPIC_AUTH_TOKEN: normalizedApiKey,
                ANTHROPIC_MODEL: normalizedModel,
            },
        },
        opencode: {
            provider: {
                default: {
                    npm: '@ai-sdk/openai-compatible',
                    options: {
                        baseURL: normalizedOpenCodeBaseUrl,
                        apiKey: normalizedApiKey,
                    },
                    models: opencodeModels,
                },
            },
        },
    };
}
function normalizeListedModels(payload) {
    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
        return [];
    }
    const records = Array.isArray(payload.data)
        ? payload.data
        : [];
    const ids = new Set();
    for (const item of records) {
        if (!item || typeof item !== 'object' || Array.isArray(item)) {
            continue;
        }
        const id = String(item.id || '').trim();
        if (id) {
            ids.add(id);
        }
    }
    return [...ids];
}
function buildModelListCandidates(baseUrl, protocol) {
    const normalizedBaseUrl = baseUrl.replace(/\/+$/, '');
    if (protocol === 'anthropic') {
        return [`${normalizedBaseUrl}/v1/models`];
    }
    if (protocol === 'openai') {
        return normalizedBaseUrl.endsWith('/v1')
            ? [`${normalizedBaseUrl}/models`]
            : [`${normalizedBaseUrl}/models`, `${normalizedBaseUrl}/v1/models`];
    }
    const openAiCandidates = normalizedBaseUrl.endsWith('/v1')
        ? [`${normalizedBaseUrl}/models`]
        : [`${normalizedBaseUrl}/models`, `${normalizedBaseUrl}/v1/models`];
    return [...openAiCandidates, `${normalizedBaseUrl}/v1/models`];
}
function buildApplyAiSourcesResponse(body) {
    return {
        acodeModelEffort: String(body.acodeModelEffort || ''),
        claudecodeModelEffort: String(body.claudecodeModelEffort || ''),
        codexModelEffort: String(body.codexModelEffort || ''),
        opencodeModelEffort: String(body.opencodeModelEffort || ''),
    };
}
describe('ai source unified config generation', () => {
    it('builds tool-specific configs from unified template fields', () => {
        assert.deepEqual(buildUnifiedToolConfig({
            baseUrl: 'https://example.com',
            apiKey: 'sk-demo',
            model: 'claude-sonnet-4-5',
            models: ['claude-sonnet-4-5', 'claude-haiku-4-5'],
        }), {
            claudecode: {
                env: {
                    ANTHROPIC_BASE_URL: 'https://example.com',
                    ANTHROPIC_AUTH_TOKEN: 'sk-demo',
                    ANTHROPIC_MODEL: 'claude-sonnet-4-5',
                },
            },
            opencode: {
                provider: {
                    default: {
                        npm: '@ai-sdk/openai-compatible',
                        options: {
                            baseURL: 'https://example.com/v1',
                            apiKey: 'sk-demo',
                        },
                        models: {
                            'claude-sonnet-4-5': {
                                name: 'claude-sonnet-4-5',
                                modalities: {
                                    input: ['text', 'image'],
                                    output: ['text'],
                                },
                            },
                            'claude-haiku-4-5': {
                                name: 'claude-haiku-4-5',
                                modalities: {
                                    input: ['text', 'image'],
                                    output: ['text'],
                                },
                            },
                        },
                    },
                },
            },
        });
    });
    it('extracts model ids from an OpenAI-compatible models payload', () => {
        expect(normalizeListedModels({
            data: [
                { id: 'claude-sonnet-4-5' },
                { id: 'claude-haiku-4-5' },
                { id: 'claude-sonnet-4-5' },
            ],
        })).toEqual(['claude-sonnet-4-5', 'claude-haiku-4-5']);
    });
    it('builds fallback candidates for openai-compatible and anthropic model listing', () => {
        expect(buildModelListCandidates('https://octopus.721579.xyz', 'openai')).toEqual([
            'https://octopus.721579.xyz/models',
            'https://octopus.721579.xyz/v1/models',
        ]);
        expect(buildModelListCandidates('https://api.anthropic.com', 'anthropic')).toEqual([
            'https://api.anthropic.com/v1/models',
        ]);
    });
    it('keeps openai-compatible baseURL unchanged when template already includes /v1', () => {
        expect(buildUnifiedToolConfig({
            baseUrl: 'https://octopus.721579.xyz/v1',
            apiKey: 'sk-demo',
            model: 'gpt-test',
        }).opencode.provider.default.options.baseURL).toBe('https://octopus.721579.xyz/v1');
    });
    it('echoes selected model effort metadata in apply-ai-sources responses', () => {
        expect(buildApplyAiSourcesResponse({
            acodeModelEffort: 'xhigh',
            claudecodeModelEffort: 'high',
            codexModelEffort: 'max',
            opencodeModelEffort: 'high',
        })).toEqual({
            acodeModelEffort: 'xhigh',
            claudecodeModelEffort: 'high',
            codexModelEffort: 'max',
            opencodeModelEffort: 'high',
        });
    });
});
