#include <catch.hpp>

#include <cstring>
#include <cds-pubsub/pub.hh>

namespace
{
    using PassThroughMessage = std::pair< pub_sub::KeyType, pub_sub::Message >;

    class PassThroughPublisher : public pub_sub::plugins::PublisherInstance
    {
    public:
        PassThroughPublisher( std::vector< PassThroughMessage >& dest )
            : dest_{ dest }
        {
        }
        ~PassThroughPublisher( ) override = default;

        void
        publish( pub_sub::KeyType key, pub_sub::Message msg ) override
        {
            dest_.emplace_back( std::make_pair( key, msg ) );
        }

        std::vector< PassThroughMessage >& dest_;
    };

    class PassThroughPublisherApi : public pub_sub::plugins::PublisherPluginApi
    {
    public:
        PassThroughPublisherApi( std::vector< PassThroughMessage >& dest )
            : dest_{ dest }
        {
        }
        ~PassThroughPublisherApi( ) override = default;

        const std::string&
        prefix( ) const override
        {
            const static std::string my_prefix = "test://";
            return my_prefix;
        }

        const std::string&
        name( ) const override
        {
            const static std::string my_name = "test";
            return my_name;
        }

        const std::string&
        version( ) const override
        {
            const static std::string my_version = "0";
            return my_version;
        }

        pub_sub::plugins::UniquePublisherInstance
        publish( const std::string&                        address,
                 pub_sub::PubDebugNotices&                 debug_hooks,
                 pub_sub::plugins::UniquePublisherInstance next_stage ) override
        {
            return std::make_unique< PassThroughPublisher >( dest_ );
        }

        std::vector< PassThroughMessage >& dest_;
    };
} // namespace

TEST_CASE( "Adding a plugin and publishing to it works" )
{
    std::vector< PassThroughMessage > dest;
    auto plugin = std::make_shared< PassThroughPublisherApi >( dest );

    pub_sub::Publisher pub;
    pub.load_plugin( plugin );
    pub.add_destination( plugin->prefix( ) + "test" );

    pub_sub::Message msg( pub_sub::DataPtr( new unsigned char[ 6 ] ), 6 );
    std::strncpy(
        reinterpret_cast< char* >( msg.data( ) ), "hello", msg.length );
    pub.publish( 42, std::move( msg ) );
    REQUIRE( dest.size( ) == 1 );
    REQUIRE( dest[ 0 ].first == 42 );
    REQUIRE( std::strcmp(
                 reinterpret_cast< const char* >( dest[ 0 ].second.data( ) ),
                 "hello" ) == 0 );
}