"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.summarizeConversationTitle = exports.deleteConversation = exports.sendMessage = exports.getConversationItems = exports.getConversations = exports.createConversation = void 0;
const ai_chat_1 = require("../components/ai-chat");
const utils_1 = require("../utils");
const sendApiError_1 = require("../utils/sendApiError");
const ERROR_MESSAGE = {
    CONFIG_NOT_SET: 'AI Chat configuration is not set in UI settings',
    CONFIG_INVALID: 'AI Chat configuration is invalid: missing required fields',
    FAILED_CREATE_CONVERSATION: 'Failed to create conversation',
    FAILED_GET_CONVERSATIONS: 'Failed to get conversations',
    FAILED_GET_CONVERSATION_ITEMS: 'Failed to get conversation items',
    STREAM_ERROR: 'Stream error:',
    FAILED_SEND_MESSAGE: 'Failed to send message',
    FAILED_DELETE_CONVERSATION: 'Failed to delete conversation',
    FAILED_UPDATE_CONVERSATION_TITLE: 'Failed to update conversation title',
};
const getAiChatConfiguration = (req) => {
    const config = req.ctx.config;
    const aiChatConfig = config.uiSettings?.aiChatConfig;
    if (!aiChatConfig) {
        throw new utils_1.ErrorWithCode(500, ERROR_MESSAGE.CONFIG_NOT_SET);
    }
    if (!aiChatConfig.baseUrl || !aiChatConfig.model) {
        throw new utils_1.ErrorWithCode(500, ERROR_MESSAGE.CONFIG_INVALID);
    }
    return aiChatConfig;
};
const getAiChatInstance = (req) => {
    const config = getAiChatConfiguration(req);
    return new ai_chat_1.AiChat(config);
};
const createConversation = async (req, res) => {
    try {
        const aiChat = getAiChatInstance(req);
        const requestData = req.body;
        const response = await aiChat.createConversation(requestData, req);
        await (0, utils_1.pipeAxiosResponse)(req.ctx, res, response);
    }
    catch (e) {
        req.ctx.logError(ERROR_MESSAGE.FAILED_CREATE_CONVERSATION, e);
        (0, sendApiError_1.sendApiError)(res, e);
    }
};
exports.createConversation = createConversation;
const getConversations = async (req, res) => {
    try {
        const aiChat = getAiChatInstance(req);
        const limit = req.query.limit ? parseInt(req.query.limit, 10) : undefined;
        const after = req.query.after;
        const response = await aiChat.getConversations(limit, after, req);
        await (0, utils_1.pipeAxiosResponse)(req.ctx, res, response);
    }
    catch (e) {
        req.ctx.logError(ERROR_MESSAGE.FAILED_GET_CONVERSATIONS, e);
        (0, sendApiError_1.sendApiError)(res, e);
    }
};
exports.getConversations = getConversations;
const getConversationItems = async (req, res) => {
    try {
        const aiChat = getAiChatInstance(req);
        const { conversationId } = req.params;
        const limit = req.query.limit ? parseInt(req.query.limit, 10) : undefined;
        const after = req.query.after;
        const order = req.query.order || 'desc';
        const response = await aiChat.getConversationItems(conversationId, limit, after, order, req);
        await (0, utils_1.pipeAxiosResponse)(req.ctx, res, response);
    }
    catch (e) {
        req.ctx.logError(ERROR_MESSAGE.FAILED_GET_CONVERSATION_ITEMS, e);
        (0, sendApiError_1.sendApiError)(res, e);
    }
};
exports.getConversationItems = getConversationItems;
const sendMessage = async (req, res) => {
    let streamClosed = false;
    let headersAlreadySent = false;
    const closeStream = () => {
        if (!streamClosed) {
            streamClosed = true;
            if (!res.writableEnded) {
                res.end();
            }
        }
    };
    try {
        const aiChat = getAiChatInstance(req);
        const { message, promptId, metadata, model, conversationId, contextMessages, files } = req.body;
        const requestData = {
            model,
            prompt: promptId ? { id: promptId } : undefined,
            conversationId,
            message,
            metadata,
            contextMessages,
            files,
        };
        res.setHeader('Content-Type', 'text/event-stream');
        res.setHeader('Cache-Control', 'no-cache');
        res.setHeader('Connection', 'keep-alive');
        res.setHeader('X-Accel-Buffering', 'no');
        res.flushHeaders();
        headersAlreadySent = true;
        const response = await aiChat.sendMessage(requestData, req);
        let lastTail = '';
        response.on('data', (chunk) => {
            if (streamClosed) {
                return;
            }
            const chunkString = lastTail + chunk.toString();
            const lines = chunkString.split('\n');
            lastTail = lines.pop() || '';
            for (const line of lines) {
                const trimmedLine = line.trim();
                if (!trimmedLine) {
                    continue;
                }
                if (trimmedLine.startsWith('data: ')) {
                    const dataContent = trimmedLine.substring(6);
                    if (dataContent === '[DONE]') {
                        continue;
                    }
                    try {
                        const data = JSON.parse(dataContent);
                        if (data.type === 'response.output_text.delta' && data.delta) {
                            res.write(`data: ${JSON.stringify({ text: data.delta })}\n\n`);
                        }
                        else {
                            if (data.type === 'response.output_text.done')
                                continue;
                            res.write(`data: ${JSON.stringify(data)}\n\n`);
                        }
                        if (data.type === 'response.done' || data.type === 'response.failed') {
                            res.write('data: [DONE]\n\n');
                            closeStream();
                            return;
                        }
                    }
                    catch (e) {
                        req.ctx.logError('Failed to parse SSE data:', e);
                    }
                }
            }
        });
        response.on('end', () => {
            if (!streamClosed) {
                res.write('data: [DONE]\n\n');
            }
            closeStream();
        });
        response.on('error', (e) => {
            if (!streamClosed) {
                req.ctx.logError(ERROR_MESSAGE.STREAM_ERROR, e);
                try {
                    res.write(`data: ${JSON.stringify({ type: 'error', error: e.message })}\n\n`);
                    res.write('data: [DONE]\n\n');
                }
                catch (writeError) {
                    req.ctx.logError('Failed to write error to stream:', writeError);
                }
            }
            closeStream();
        });
        req.on('close', () => {
            if (!streamClosed) {
                req.ctx.logError('Client disconnected');
                response.destroy();
                closeStream();
            }
        });
    }
    catch (e) {
        req.ctx.logError(ERROR_MESSAGE.FAILED_SEND_MESSAGE, e);
        if (headersAlreadySent && !streamClosed) {
            try {
                res.write(`data: ${JSON.stringify({ type: 'error', error: e.message })}\n\n`);
                res.write('data: [DONE]\n\n');
            }
            catch (writeError) {
                req.ctx.logError('Failed to write error to stream:', writeError);
            }
            closeStream();
        }
        else if (!headersAlreadySent) {
            (0, sendApiError_1.sendApiError)(res, e);
        }
    }
};
exports.sendMessage = sendMessage;
const deleteConversation = async (req, res) => {
    try {
        const aiChat = getAiChatInstance(req);
        const { conversationId } = req.params;
        const response = await aiChat.deleteConversation(conversationId, req);
        await (0, utils_1.pipeAxiosResponse)(req.ctx, res, response);
    }
    catch (e) {
        req.ctx.logError(ERROR_MESSAGE.FAILED_DELETE_CONVERSATION, e);
        (0, sendApiError_1.sendApiError)(res, e);
    }
};
exports.deleteConversation = deleteConversation;
const summarizeConversationTitle = async (req, res) => {
    try {
        const aiChat = getAiChatInstance(req);
        const { conversationId } = req.params;
        const title = await aiChat.summarizeConversationTitle(conversationId, req);
        res.status(200).json({ success: true, title });
    }
    catch (e) {
        req.ctx.logError(ERROR_MESSAGE.FAILED_UPDATE_CONVERSATION_TITLE, e);
        (0, sendApiError_1.sendApiError)(res, e);
    }
};
exports.summarizeConversationTitle = summarizeConversationTitle;
