#pragma once

#include "ProtobufMessages.hpp"
#include "message_protocol/MessageConnection.hpp"
#include "message_protocol/MessageEndpoint.hpp"

#include <memory>
#include <string>
#include <vector>

#include <spdlog/spdlog.h>

namespace tw::net {

// Listens on a dedicated port for incoming zone-server peer connections and
// opens outgoing connections to known peers.
//
// Incoming and outgoing peers are held together so that broadcast messages
// (ZoneHello, ZoneBye) reach every peer uniformly.
class ZoneClusterLink {
    std::unique_ptr<msg::MessageEndpoint> m_endpoint;
    ProtobufMessages                      m_messages;

public:
    explicit ZoneClusterLink(int port);

    // Poll for messages and accept any pending peer connections.
    void update();

    // Connect to a remote zone peer and register it in the peer list.
    msg::MessageConnection* connect_to_peer(const std::string& host, int port);

    // Send a protobuf message to a single peer.
    template<typename T>
    void send_mesg(msg::MessageConnection* peer, const T& msg) {
        auto send_r = m_messages.send(peer, msg, false);
        if(!send_r) {
            spdlog::error("ZoneClusterLink: failed to send to peer {}: {}",
                          peer->peer_id(), send_r.error().message());
        }
    }

    // Send a protobuf message to all connected peers.
    template<typename T>
    void broadcast(const T& msg) {
        m_messages.broadcast(msg);
    }

    std::vector<msg::MessageConnection*> peers() const {
        return m_endpoint->peers();
    }

    msg::MessageEndpoint& endpoint() {
        return *m_endpoint;
    }
};

} // namespace tw::net
