#include "message_protocol/MessageDispatcher.hpp"

#include <catch2/catch_test_macros.hpp>

#include <array>
#include <string>

using namespace tw::msg;

namespace {

std::span<const std::byte> as_bytes(const std::array<std::byte, 2>& body) {
    return { body.data(), body.size() };
}

}

TEST_CASE("Dispatch reaches the handler bound to the address", "[message_dispatcher]") {
    MessageDispatcher dispatcher;

    PeerId seen_peer = 0;
    size_t seen_size = 0;

    dispatcher.set_handler(7, [&](PeerId peer, std::span<const std::byte> body) {
        seen_peer = peer;
        seen_size = body.size();
    });

    std::array<std::byte, 2> body{};

    REQUIRE(dispatcher.dispatch(99, 7, as_bytes(body)));
    REQUIRE(seen_peer == 99);
    REQUIRE(seen_size == 2);
}

TEST_CASE("Dispatch to an unbound address reports failure", "[message_dispatcher]") {
    MessageDispatcher dispatcher;

    std::array<std::byte, 2> body{};

    REQUIRE_FALSE(dispatcher.dispatch(1, 7, as_bytes(body)));
}

TEST_CASE("Addresses are routed independently", "[message_dispatcher]") {
    MessageDispatcher dispatcher;

    std::string called;

    dispatcher.set_handler(1, [&](PeerId, std::span<const std::byte>) { called = "first"; });
    dispatcher.set_handler(2, [&](PeerId, std::span<const std::byte>) { called = "second"; });

    std::array<std::byte, 2> body{};

    dispatcher.dispatch(1, 2, as_bytes(body));
    REQUIRE(called == "second");

    dispatcher.dispatch(1, 1, as_bytes(body));
    REQUIRE(called == "first");
}

TEST_CASE("Rebinding an address replaces the handler", "[message_dispatcher]") {
    MessageDispatcher dispatcher;

    std::string called;

    dispatcher.set_handler(7, [&](PeerId, std::span<const std::byte>) { called = "first"; });
    dispatcher.set_handler(7, [&](PeerId, std::span<const std::byte>) { called = "second"; });

    std::array<std::byte, 2> body{};
    dispatcher.dispatch(1, 7, as_bytes(body));

    REQUIRE(called == "second");
}
