/*
 * Copyright 2024 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef GENAI_NLP_SERVICE_PROXY_H
#define GENAI_NLP_SERVICE_PROXY_H

#include <jsoncpp/json/json.h>

#include <functional>

#include "_chatmodelconfig.h"
#include "chat.h"
#include "genainlpserver.h"

namespace kyai::genai::nlp {

using ReconnectedCallback = std::function<void()>;

class GenAiNlpServiceProxy {
public:
    ~GenAiNlpServiceProxy();

    bool connectToServer();
    bool reconnectServer();

    int initEngine(const ChatModelConfig &chatModelConfig, int *sessionId);

    void destroyEngine(int sessionId);

    void setChatResultCallback(const ChatResultCallback &callback,
                               void *userData);

    void setReconnectedCallback(const ReconnectedCallback &callback);

    void chat(int sessionId, const ChatModelConfig &chatModelConfig,
              const std::string &question);

    void stopChat(int sessionId);

    void clearChatMessage(int sessionId);

    void setChatSystemPromptId(int sessionId, PromptId promptId);

    void addSystemMessage(int sessionId, const std::string &message);

    void chatWithHistoryMessages(int sessionId,
                                 const ChatModelConfig &chatModelConfig,
                                 const std::string &messages);

private:
    void connectChatResultSignals(int sessionId);

    static void onChatResultCallback(GDBusConnection *connection,
                                     const gchar *senderName,
                                     const gchar *objectPath,
                                     const gchar *interfaceName,
                                     const gchar *signalName,
                                     GVariant *parameters, gpointer userData);
    static void onChatFinishedCallback(GObject *sourceObject, GAsyncResult *res,
                                       gpointer userData);

    void handleErrorOccurred(int errorCode);
    void handleServerClosed();
    void handleChatTimeout();
    void handleGeneralError();
    void handleMessagesEmptyError();

    void startCallbackTimer();
    void removeCallbackTimerIfExists();
    void resetCallbackTimer();
    void handleCallbackTimeout();

private:
    ChatResultCallback chatResultCallback_{nullptr};
    ReconnectedCallback reconnectedCallback_{nullptr};
    void *userData_{nullptr};

    AiRuntimeGenAiNlpService *proxy_{nullptr};
    GenAiNlpServer *genNlpServer_{nullptr};
    int currentSessionId_{0};
    guint subscriptionId_{0};
    guint timeoutId_{0};
    int reconnectAttempts_{0};
    static constexpr int maxReconnectAttempts = 10;
};

}  // namespace kyai::genai::nlp
#endif  // GENAI_NLP_SERVICE_PROXY_H
