// DragonX Wallet - HushChat in-memory message store (implementation).

#include "chat_store.h"

#include <algorithm>

namespace dragonx::chat {

std::string ChatStore::dedupKey(const ChatMessage& message) {
    return message.txid + ":" + std::to_string(message.payload_position);
}

bool ChatStore::append(const ChatMessage& message) {
    if (!seen_.insert(dedupKey(message)).second) return false;
    messages_.push_back(message);
    ++revision_;
    return true;
}

std::vector<ChatMessage> ChatStore::conversation(const std::string& conversationId) const {
    std::vector<ChatMessage> out;
    for (const auto& message : messages_) {
        if (message.conversation_id == conversationId) out.push_back(message);
    }
    // Return chronological (oldest→newest). messages_ is in scan/insertion order, which is NOT
    // time-ordered (a full scan harvests txids in std::set/unordered_map order) — that would mis-order the
    // rendered thread AND let the reply-target pin (first-seen peer address) latch onto a non-establishing
    // message (B2). timestamp is the block/tx time (peer can't set it); tie-break txid + payload_position
    // for determinism.
    std::stable_sort(out.begin(), out.end(), [](const ChatMessage& a, const ChatMessage& b) {
        if (a.timestamp != b.timestamp) return a.timestamp < b.timestamp;
        if (a.txid != b.txid) return a.txid < b.txid;
        return a.payload_position < b.payload_position;
    });
    return out;
}

const ChatMessage* ChatStore::updateDelivery(const std::string& txid, ChatDelivery delivery) {
    for (auto& message : messages_) {
        if (message.txid == txid) {
            message.delivery = delivery;
            ++revision_;
            return &message;
        }
    }
    return nullptr;
}

int ChatStore::countUnread(const std::function<bool(const std::string&)>& excluded,
                           const std::function<std::int64_t(const std::string&)>& seenFor) const {
    int unread = 0;
    for (const auto& m : messages_) {
        if (m.direction != ChatDirection::Incoming) continue;
        if (excluded && excluded(m.conversation_id)) continue;
        if (m.timestamp > seenFor(m.conversation_id)) ++unread;
    }
    return unread;
}

std::vector<std::string> ChatStore::conversationIds() const {
    std::vector<std::string> ids;
    std::unordered_set<std::string> seenIds;
    for (const auto& message : messages_) {
        if (seenIds.insert(message.conversation_id).second) ids.push_back(message.conversation_id);
    }
    return ids;
}

std::vector<ChatMessage> ChatStore::eraseConversation(const std::string& conversationId) {
    std::vector<ChatMessage> removed;
    std::vector<ChatMessage> kept;
    kept.reserve(messages_.size());
    for (auto& m : messages_) {
        if (m.conversation_id == conversationId) {
            seen_.erase(dedupKey(m));
            removed.push_back(std::move(m));
        } else {
            kept.push_back(std::move(m));
        }
    }
    messages_.swap(kept);
    if (!removed.empty()) ++revision_;
    return removed;
}

void ChatStore::clear() {
    messages_.clear();
    seen_.clear();
    ++revision_;
}

} // namespace dragonx::chat
