import { PassThrough } from 'node:stream';
import { DEFAULT_GEMINI_CONVERSION_CONFIG } from '../types/index.js';
import { ErrorUtils } from '../shared/utils.js';
import { createGeminiSequencer } from './sequencers/gemini-sequencer.js';
import { createGeminiStreamWriter } from '../shared/writer.js';
export class GeminiJsonToSseConverter {
    config = DEFAULT_GEMINI_CONVERSION_CONFIG;
    contexts = new Map();
    constructor(config) {
        if (config) {
            this.config = { ...this.config, ...config };
        }
    }
    async convertResponseToJsonToSse(response, options) {
        const context = this.createContext(response, options);
        this.contexts.set(options.requestId, context);
        const stream = new PassThrough({ objectMode: true });
        const writer = createGeminiStreamWriter(stream, {
            onEvent: () => this.updateStats(context, 'chunk'),
            onError: (error) => this.handleStreamError(context, error, stream)
        });
        this.processResponse(response, context, writer, stream).catch((error) => {
            this.handleStreamError(context, error, stream);
        });
        return Object.assign(stream, {
            protocol: 'gemini-chat',
            direction: 'json_to_sse',
            requestId: options.requestId,
            getStats: () => context.eventStats,
            complete: () => writer.complete(),
            abort: (error) => writer.abort(error)
        });
    }
    createContext(response, options) {
        const stats = {
            totalEvents: 0,
            chunkEvents: 0,
            doneEvents: 0,
            errors: 0,
            startTime: Date.now()
        };
        return {
            requestId: options.requestId,
            model: options.model,
            response,
            options,
            startTime: Date.now(),
            eventStats: stats
        };
    }
    async processResponse(response, context, writer, stream) {
        try {
            this.validateResponse(response);
            const sequencer = createGeminiSequencer({
                chunkDelayMs: context.options.chunkDelayMs ?? this.config.chunkDelayMs,
                reasoningMode: context.options.reasoningMode ?? this.config.reasoningMode,
                reasoningTextPrefix: context.options.reasoningTextPrefix ?? this.config.reasoningTextPrefix
            });
            const events = sequencer.sequenceResponse(response);
            await writer.writeGeminiEvents(events);
            this.updateStats(context, 'done');
            writer.complete();
        }
        catch (error) {
            writer.abort(error);
            throw this.wrapError('GEMINI_JSON_TO_SSE_FAILED', error, context.requestId);
        }
        finally {
            this.contexts.delete(context.requestId);
            stream.end();
        }
    }
    validateResponse(response) {
        if (!response || typeof response !== 'object') {
            throw new Error('Invalid Gemini response payload');
        }
    }
    updateStats(context, kind) {
        context.eventStats.totalEvents += 1;
        if (kind === 'chunk') {
            context.eventStats.chunkEvents += 1;
        }
        else {
            context.eventStats.doneEvents += 1;
        }
    }
    handleStreamError(context, error, stream) {
        context.eventStats.errors += 1;
        try {
            stream.destroy(error);
        }
        catch {
            /* ignore */
        }
    }
    wrapError(code, error, requestId) {
        return ErrorUtils.createError(error.message, code, { requestId });
    }
}
