/* Connection string stage parsing helper
Copyright (C) 2026 Jonathan Hanks

This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
#include <cds-pubsub/stage_address.hh>

#include <sstream>
#include <stdexcept>
#include <vector>

#include <boost/algorithm/string.hpp>

namespace pub_sub
{
    StageAddress
    parse_stage_address( const std::string& stage )
    {
        StageAddress result{ };

        auto scheme_end = stage.find( "://" );
        if ( scheme_end == std::string::npos || scheme_end == 0 )
        {
            std::ostringstream os;
            os << "The stage '" << stage
               << "' must have the form scheme://path[?key=value&...]";
            throw std::runtime_error( os.str( ) );
        }
        result.scheme = stage.substr( 0, scheme_end );

        auto rest = stage.substr( scheme_end + 3 );
        auto query_start = rest.find( '?' );
        result.path = rest.substr( 0, query_start );
        if ( query_start == std::string::npos )
        {
            return result;
        }

        auto query = rest.substr( query_start + 1 );
        if ( query.empty( ) )
        {
            return result;
        }

        std::vector< std::string > components;
        boost::split( components, query, boost::is_any_of( "&" ) );
        for ( const auto& component : components )
        {
            auto separator = component.find( '=' );
            if ( component.empty( ) || separator == std::string::npos ||
                 separator == 0 )
            {
                std::ostringstream os;
                os << "The stage '" << stage
                   << "' has a malformed argument; arguments must be "
                      "key=value pairs separated by '&'";
                throw std::runtime_error( os.str( ) );
            }
            auto key = component.substr( 0, separator );
            auto value = component.substr( separator + 1 );
            if ( !result.arguments
                      .emplace( std::move( key ), std::move( value ) )
                      .second )
            {
                std::ostringstream os;
                os << "The stage '" << stage << "' repeats the argument '"
                   << component.substr( 0, separator ) << "'";
                throw std::runtime_error( os.str( ) );
            }
        }
        return result;
    }
} // namespace pub_sub
