import { parseModelPrefix, makeModelId, providerLabel } from '../src/features/providers/types';
import { _internals } from '../src/features/providers/streamHelpers';

describe('parseModelPrefix', () => {
    test('matches openrouter / anthropic / gemini prefixes', () => {
        expect(parseModelPrefix('openrouter:anthropic/claude-3.5-sonnet')).toEqual({
            provider: 'openrouter', model: 'anthropic/claude-3.5-sonnet',
        });
        expect(parseModelPrefix('anthropic:claude-3-5-sonnet-20241022')).toEqual({
            provider: 'anthropic', model: 'claude-3-5-sonnet-20241022',
        });
        expect(parseModelPrefix('gemini:gemini-2.0-flash-exp')).toEqual({
            provider: 'gemini', model: 'gemini-2.0-flash-exp',
        });
    });

    test('returns null for local engine model ids', () => {
        expect(parseModelPrefix('gemma4:e2b')).toBeNull();
        expect(parseModelPrefix('llama-3.2:8b')).toBeNull();
        expect(parseModelPrefix('google/gemma-4-e4b')).toBeNull();
    });

    test('returns null for empty / undefined input', () => {
        expect(parseModelPrefix('')).toBeNull();
        expect(parseModelPrefix(undefined as any)).toBeNull();
    });

    test('makeModelId round-trips with parseModelPrefix', () => {
        const id = makeModelId('openrouter', 'meta/llama-3.3-70b');
        expect(id).toBe('openrouter:meta/llama-3.3-70b');
        expect(parseModelPrefix(id)).toEqual({ provider: 'openrouter', model: 'meta/llama-3.3-70b' });
    });

    test('providerLabel returns Korean-friendly labels', () => {
        expect(providerLabel('openrouter')).toBe('OpenRouter');
        expect(providerLabel('anthropic')).toBe('Anthropic');
        expect(providerLabel('gemini')).toBe('Gemini');
    });
});

describe('Anthropic event → OpenAI SSE conversion', () => {
    const conv = _internals.anthropicEventToOpenAI;

    test('content_block_delta with text emits OpenAI chunk', () => {
        const out = conv('content_block_delta', '{"delta":{"type":"text_delta","text":"안녕"}}');
        expect(out).toBeTruthy();
        expect(out).toContain('"content":"안녕"');
        expect(out).toMatch(/^data: /);
        expect(out!.endsWith('\n\n')).toBe(true);
    });

    test('non-delta events (message_start, content_block_start, etc.) are ignored', () => {
        expect(conv('message_start', '{}')).toBeNull();
        expect(conv('content_block_start', '{}')).toBeNull();
        expect(conv('message_stop', '{}')).toBeNull();
    });

    test('malformed JSON returns null', () => {
        expect(conv('content_block_delta', 'not json')).toBeNull();
        expect(conv('content_block_delta', '{')).toBeNull();
    });

    test('empty text field returns null (no zero-length chunks)', () => {
        expect(conv('content_block_delta', '{"delta":{"type":"text_delta","text":""}}')).toBeNull();
        expect(conv('content_block_delta', '{"delta":{}}')).toBeNull();
    });
});

describe('Gemini event → OpenAI SSE conversion', () => {
    const conv = _internals.geminiEventToOpenAI;

    test('extracts text from candidates[0].content.parts', () => {
        const out = conv(null, '{"candidates":[{"content":{"parts":[{"text":"안녕"}],"role":"model"}}]}');
        expect(out).toBeTruthy();
        expect(out).toContain('"content":"안녕"');
        expect(out).toMatch(/^data: /);
    });

    test('joins multiple parts into one chunk', () => {
        const out = conv(null, '{"candidates":[{"content":{"parts":[{"text":"안"},{"text":"녕"}]}}]}');
        expect(out).toContain('"content":"안녕"');
    });

    test('returns null when candidates missing / empty', () => {
        expect(conv(null, '{}')).toBeNull();
        expect(conv(null, '{"candidates":[]}')).toBeNull();
        expect(conv(null, '{"candidates":[{"content":{}}]}')).toBeNull();
    });

    test('malformed JSON returns null', () => {
        expect(conv(null, 'not json')).toBeNull();
    });

    test('empty text returns null', () => {
        expect(conv(null, '{"candidates":[{"content":{"parts":[{"text":""}]}}]}')).toBeNull();
    });
});
