#pragma once

#include "PeerLink.hpp"
#include "quicr/QuicrConnection.hpp"
#include "quicr/QuicrConnectionListener.hpp"
#include "quicr/QuicrEndpoint.hpp"

#include <list>
#include <optional>
#include <unordered_map>
#include <vector>

namespace tw::p2p {

class QuicrPeerLink : public PeerLink {
public:
    QuicrPeerLink(uint32_t self_id, uint16_t port);

    void connect_to(uint32_t peer_id, const tw::net::Address& addr) override;
    void send_batch(uint32_t peer_id, const mmo::peer::PeerActionBatch& batch) override;
    void poll      () override;

private:
    enum class MsgType : uint32_t { Hello = 1, ActionBatch = 2, Bye = 3 };

    struct Conn {
        tw::net::quicr::QuicrConnection* raw;
        std::optional<uint32_t>          peer_id;
        std::vector<std::byte>           recv_buf{64 * 1024};
    };

    uint32_t m_self_id;
    std::unique_ptr<tw::net::quicr::QuicrEndpoint>           m_endpoint;
    std::unique_ptr<tw::net::quicr::QuicrConnectionListener> m_listener;

    std::list<Conn> m_conns;
    std::unordered_map<uint32_t, tw::net::quicr::QuicrConnection*> m_by_id;

    void send_raw     (tw::net::quicr::QuicrConnection* conn, MsgType type,
                       const google::protobuf::MessageLite& msg, bool reliable);
    void dispatch     (Conn& c, std::span<const std::byte> frame);
    void drain_listener();
    void poll_conns   ();
};

} // namespace tw::p2p
