#include <catch.hpp>

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

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

    class PassThroughSubscriberApi
        : public pub_sub::plugins::SubscriptionPluginApi
    {
    public:
        PassThroughSubscriberApi( std::vector< PassThroughMessage >& source )
            : source_{ source }
        {
        }
        ~PassThroughSubscriberApi( ) 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;
        }

        std::shared_ptr< pub_sub::plugins::Subscription >
        subscribe( const std::string&        address,
                   pub_sub::SubDebugNotices& debug_hooks,
                   pub_sub::SubHandler       handler ) override
        {
            auto sub = std::make_shared< pub_sub::plugins::Subscription >( );
            auto id = sub->sub_id( );
            std::for_each(
                source_.begin( ),
                source_.end( ),
                [ id, &handler ]( PassThroughMessage& msg ) {
                    handler( pub_sub::SubMessage( id, msg.first, msg.second ) );
                } );
            return sub;
        }

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

TEST_CASE( "Adding a plugin and subscribing to it works" )
{
    std::vector< PassThroughMessage >  source;
    std::vector< pub_sub::SubMessage > dest;

    auto plugin = std::make_shared< PassThroughSubscriberApi >( source );
    {
        pub_sub::Message msg( pub_sub::DataPtr( new unsigned char[ 6 ] ), 6 );
        std::strncpy(
            reinterpret_cast< char* >( msg.data( ) ), "hello", msg.length );
        source.emplace_back( std::make_pair( 42, msg ) );
    }

    pub_sub::Subscriber sub;
    sub.load_plugin( plugin );
    auto id = sub.subscribe( plugin->prefix( ) + "test",
                             [ &dest ]( pub_sub::SubMessage msg ) {
                                 dest.emplace_back( std::move( msg ) );
                             } );

    REQUIRE( dest.size( ) == 1 );
    REQUIRE( dest[ 0 ].sub_id( ) == id );
    REQUIRE( dest[ 0 ].key( ) == 42 );
    REQUIRE( dest[ 0 ].message( ).length == 6 );
    REQUIRE( std::strcmp( reinterpret_cast< const char* >( dest[ 0 ].data( ) ),
                          "hello" ) == 0 );
}