/*****************************************************************************
 * Copyright (c) 2014-2026 OpenRCT2 developers
 *
 * For a complete list of all authors, please refer to contributors.md
 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
 *
 * OpenRCT2 is licensed under the GNU General Public License version 3.
 *****************************************************************************/

#include "../OpenRCT2.h"
#include "../core/Console.hpp"
#include "../core/String.hpp"
#include "../network/Network.h"
#include "CommandLine.hpp"
#include "ExitCode.h"

using namespace OpenRCT2::CommandLine;

namespace OpenRCT2
{
    static ExitCode HandleUri(const std::string& uri);

#ifndef DISABLE_NETWORK
    static ExitCode HandleUriJoin(const std::vector<std::string_view>& args);
    static bool TryParseHostnamePort(
        std::string_view hostnamePort, std::string* outHostname, int32_t* outPort, int32_t defaultPort);
#endif

    ExitCode CommandLine::HandleCommandUri(CommandLineArgEnumerator* enumerator)
    {
        const utf8* uri;
        if (enumerator->TryPopString(&uri))
        {
            if (String::startsWith(uri, "openrct2://"))
            {
                const utf8* uriCommand = uri + 11;
                return HandleUri(uriCommand);
            }
        }

        Console::Error::WriteLine("Invalid URI");
        return ExitCode::fail;
    }

    static ExitCode HandleUri(const std::string& uri)
    {
        ExitCode result = ExitCode::launch;
        auto args = String::split(uri, "/");
        if (!args.empty())
        {
#ifndef DISABLE_NETWORK
            const auto arg = args[0];
            if (arg == "join")
            {
                result = HandleUriJoin(args);
            }
#endif
        }
        return result;
    }

#ifndef DISABLE_NETWORK

    static ExitCode HandleUriJoin(const std::vector<std::string_view>& args)
    {
        std::string hostname;
        int32_t port;
        if (args.size() > 1 && TryParseHostnamePort(args[1], &hostname, &port, Network::kDefaultPort))
        {
            // Set the network start configuration
            gNetworkStart = Network::Mode::client;
            gNetworkStartHost = std::move(hostname);
            gNetworkStartPort = port;
            return ExitCode::launch;
        }

        Console::Error::WriteLine("Expected hostname:port after join");
        return ExitCode::fail;
    }

    static bool TryParseHostnamePort(
        const std::string_view hostnamePort, std::string* outHostname, int32_t* outPort, int32_t defaultPort)
    {
        try
        {
            // Argument is in hostname:port format, so we need to split
            std::string hostname{ hostnamePort };
            int32_t port = defaultPort;
            size_t colonIndex = hostnamePort.find_first_of(':');
            if (colonIndex != std::string::npos)
            {
                hostname = hostnamePort.substr(0, colonIndex);
                port = String::parse<int32_t>(hostnamePort.substr(colonIndex + 1));
            }
            *outPort = port;
            *outHostname = std::move(hostname);
            return true;
        }
        catch (const std::exception&)
        {
            return false;
        }
    }

#endif // DISABLE_NETWORK
} // namespace OpenRCT2
