"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DifyProvider = void 0;
const http_1 = require("../http");
const shared_1 = require("../shared");
const logger_1 = __importDefault(require("../../logger"));
class DifyProvider {
    constructor(config, options = {}) {
        this.config = options.config || {};
        this.providerConfig = {
            ...config,
            responseMode: config?.responseMode || 'streaming',
            user: config?.user || 'abc-123',
        };
        // Create HttpProvider with Dify-specific configuration for blocking mode
        const httpProviderConfig = {
            url: `${config.url}/v1/chat-messages`,
            method: 'POST',
            headers: {
                Authorization: `Bearer ${config.apiKey}`,
                'Content-Type': 'application/json',
            },
            body: {
                inputs: {},
                query: '{{prompt}}',
                response_mode: this.providerConfig.responseMode,
                conversation_id: this.providerConfig.conversationId || '',
                user: this.providerConfig.user,
                auto_generate_name: true,
            },
            transformResponse: options.config?.transformResponse || 'json.answer || json.output || json',
        };
        this.httpProvider = new http_1.HttpProvider(httpProviderConfig.url, {
            ...options,
            config: httpProviderConfig,
        });
    }
    id() {
        return `dify:${this.providerConfig.url}`;
    }
    async parseSSEStream(reader) {
        const decoder = new TextDecoder();
        let answer = '';
        let metadata = null;
        let buffer = '';
        try {
            while (true) {
                const { done, value } = await reader.read();
                if (done) {
                    break;
                }
                buffer += decoder.decode(value, { stream: true });
                const lines = buffer.split('\n');
                buffer = lines.pop() || ''; // Keep incomplete line in buffer
                for (const line of lines) {
                    const trimmedLine = line.trim();
                    if (!trimmedLine || !trimmedLine.startsWith('data: ')) {
                        continue;
                    }
                    try {
                        const jsonStr = trimmedLine.substring(6); // Remove "data: " prefix
                        if (jsonStr === '[DONE]') {
                            continue;
                        }
                        const event = JSON.parse(jsonStr);
                        // Accumulate answer from agent_message events
                        if (event.event === 'agent_message' && event.answer !== undefined) {
                            answer += event.answer;
                        }
                        // Capture metadata from message_end event
                        if (event.event === 'message_end' && event.metadata) {
                            metadata = event.metadata;
                        }
                    }
                    catch (parseError) {
                        logger_1.default.debug(`[Dify Provider]: Failed to parse SSE event: ${trimmedLine} - ${parseError}`);
                    }
                }
            }
            // Process any remaining buffer
            if (buffer.trim()) {
                const trimmedLine = buffer.trim();
                if (trimmedLine.startsWith('data: ')) {
                    try {
                        const jsonStr = trimmedLine.substring(6);
                        const event = JSON.parse(jsonStr);
                        if (event.event === 'agent_message' && event.answer !== undefined) {
                            answer += event.answer;
                        }
                        if (event.event === 'message_end' && event.metadata) {
                            metadata = event.metadata;
                        }
                    }
                    catch (parseError) {
                        logger_1.default.debug(`[Dify Provider]: Failed to parse SSE event: ${trimmedLine} - ${parseError.message}`);
                    }
                }
            }
        }
        finally {
            reader.releaseLock();
        }
        return { answer, metadata };
    }
    async callApi(prompt, context) {
        logger_1.default.debug(`[Dify Provider]: Calling API with url: ${this.providerConfig.url}, mode: ${this.providerConfig.responseMode}`);
        // For blocking mode, use HttpProvider
        if (this.providerConfig.responseMode === 'blocking') {
            return this.httpProvider.callApi(prompt, context);
        }
        // For streaming mode, handle SSE stream manually
        try {
            const url = `${this.providerConfig.url}/v1/chat-messages`;
            const body = JSON.stringify({
                inputs: {},
                query: prompt,
                response_mode: 'streaming',
                conversation_id: this.providerConfig.conversationId || '',
                user: this.providerConfig.user,
                auto_generate_name: true,
            });
            const response = await fetch(url, {
                method: 'POST',
                headers: {
                    Authorization: `Bearer ${this.providerConfig.apiKey}`,
                    'Content-Type': 'application/json',
                },
                body,
                signal: AbortSignal.timeout(shared_1.REQUEST_TIMEOUT_MS),
            });
            if (!response.ok) {
                const errorText = await response.text();
                throw new Error(`Dify API error: ${response.status} ${response.statusText} - ${errorText}`);
            }
            if (!response.body) {
                throw new Error('Dify API returned empty response body');
            }
            // Parse SSE stream
            const reader = response.body.getReader();
            const { answer, metadata } = await this.parseSSEStream(reader);
            if (!answer) {
                throw new Error('No answer received from Dify streaming response');
            }
            logger_1.default.debug(`[Dify Provider]: Received streaming response with ${answer.length} characters`);
            return {
                output: answer,
                metadata: {
                    ...metadata,
                    responseMode: 'streaming',
                },
                tokenUsage: metadata?.usage
                    ? {
                        total: metadata.usage.total_tokens || 0,
                        prompt: metadata.usage.prompt_tokens || 0,
                        completion: metadata.usage.completion_tokens || 0,
                    }
                    : undefined,
            };
        }
        catch (err) {
            logger_1.default.error(`[Dify Provider]: Error calling streaming API: ${String(err)}`);
            return {
                error: `Dify streaming API error: ${String(err)}`,
            };
        }
    }
}
exports.DifyProvider = DifyProvider;
//# sourceMappingURL=dify.js.map