// DragonX Wallet - HushChat service (implementation).

#include "chat_service.h"

#include "chat_database.h"
#include "chat_identity.h"  // chatIdentityPublicKeyHex

#include <utility>

namespace dragonx::chat {

ChatService::~ChatService() {
    clearIdentity();
}

void ChatService::setIdentity(const ChatKeyPair& keys) {
    identity_ = keys;
    has_identity_ = true;
}

void ChatService::clearIdentity() {
    wipeChatKeyPair(identity_);
    has_identity_ = false;
}

int ChatService::ingest(const std::vector<HushChatTransactionMetadata>& metadata,
                        const std::unordered_map<std::string, std::int64_t>& txTimestamps,
                        std::int64_t fallbackTimestamp) {
    if (!has_identity_) return 0;

    int added = 0;
    for (const auto& meta : metadata) {
        ChatMessage message;
        message.direction = ChatDirection::Incoming;
        message.txid = meta.txid;
        message.conversation_id = meta.conversation_id;
        message.peer_zaddr = meta.reply_zaddr;
        message.peer_public_key_hex = meta.sender_public_key_hex;
        const auto timeIt = txTimestamps.find(meta.txid);
        message.timestamp = timeIt != txTimestamps.end() ? timeIt->second : fallbackTimestamp;
        message.payload_position = meta.payload_position;

        if (meta.type == HushChatHeaderType::ContactRequest) {
            message.kind = ChatMessageKind::ContactRequest;
            message.body = meta.payload_memo;  // plaintext request text
        } else {
            message.kind = ChatMessageKind::Message;
            std::string plaintext;
            const ChatCryptoStatus status = decryptIncoming(
                identity_, meta.sender_public_key_hex, meta.secretstream_header_hex,
                meta.payload_memo, plaintext);
            if (status != ChatCryptoStatus::Ok) continue;  // drop undecryptable silently
            message.body = std::move(plaintext);
        }

        // In-memory store dedups (txid+position); only persist the genuinely new ones. On the next
        // session loadFromDatabase() repopulates the store, so re-scanning the chain re-ingests but
        // the store dedup prevents a duplicate write.
        if (store_.append(message)) {
            if (db_) db_->append(message);
            ++added;
        }
    }
    return added;
}

void ChatService::loadFromDatabase() {
    if (!db_) return;
    for (const auto& message : db_->load()) {
        store_.append(message);
    }
}

std::string ChatService::identityPublicKeyHex() const {
    if (!has_identity_) return {};
    return chatIdentityPublicKeyHex(identity_);
}

ChatComposeStatus ChatService::composeMessage(const std::string& myReplyZaddr,
                                              const std::string& peerPublicKeyHex,
                                              const std::string& peerZaddr,
                                              const std::string& conversationId,
                                              const std::string& plaintext,
                                              OutgoingChatMemos& out) const {
    if (!has_identity_) return ChatComposeStatus::MissingField;
    return buildOutgoingMessage(identity_, chatIdentityPublicKeyHex(identity_), myReplyZaddr,
                                peerPublicKeyHex, peerZaddr, conversationId, plaintext, out);
}

ChatComposeStatus ChatService::composeContactRequest(const std::string& myReplyZaddr,
                                                     const std::string& peerZaddr,
                                                     const std::string& conversationId,
                                                     const std::string& requestText,
                                                     OutgoingChatMemos& out) const {
    if (!has_identity_) return ChatComposeStatus::MissingField;
    return buildOutgoingContactRequest(chatIdentityPublicKeyHex(identity_), myReplyZaddr,
                                       peerZaddr, conversationId, requestText, out);
}

bool ChatService::recordOutgoing(const ChatMessage& message) {
    if (store_.append(message)) {
        if (db_) db_->append(message);
        return true;
    }
    return false;
}

} // namespace dragonx::chat
