/*
 *
 * This file is a part of the LinkAhead Project.
 *
 * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
 * Copyright (C) 2021-2024 IndiScale GmbH <info@indiscale.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 *
 */
#ifdef BUILD_ACM
#include "linkahead/acm/user.h" // for User
#endif
#include "linkahead/certificate_provider.h" // for PemCertificateProvider
#include "linkahead/configuration.h"        // for InsecureConnectionConfigura...
#include "linkahead/connection.h"           // for ConnectionManager
#include "linkahead/exceptions.h"           // for ConnectionConfigurationError
#include "linkahead_test_utility.h"         // for EXPECT_THROW_MESSAGE, TEST_...
#include <gtest/gtest.h>
#include <gtest/gtest-message.h>   // for Message
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPartR...
#include <gtest/gtest_pred_impl.h> // for AssertionResult, TestInfo
#include <memory>                  // for allocator, operator!=, shar...
#include <string>                  // for operator+, string

namespace linkahead::connection {
#ifdef BUILD_ACM
using linkahead::acm::User;
#endif
using linkahead::configuration::ConfigurationManager;
using linkahead::configuration::InsecureConnectionConfiguration;
using linkahead::configuration::PemCertificateProvider;
using linkahead::configuration::TlsConnectionConfiguration;

class test_connection : public ::testing::Test {
protected:
  void SetUp() override {
    ConfigurationManager::Clear();
    ConfigurationManager::LoadSingleJSONConfiguration(TEST_DATA_DIR + "/test_linkahead_client.json");
  };
  void TearDown() override { ConfigurationManager::Clear(); };
};

TEST_F(test_connection, configure_insecure_localhost_8080) {
  InsecureConnectionConfiguration configuration("localhost", 8000);

  EXPECT_EQ("localhost", configuration.GetHost());
  EXPECT_EQ(8000, configuration.GetPort());
  auto icc = configuration.GetChannelCredentials();
  EXPECT_TRUE(icc != nullptr);
}

TEST_F(test_connection, configure_ssl_localhost_8080) {
  auto cacert = PemCertificateProvider("ca chain");
  TlsConnectionConfiguration configuration("localhost", 44300, cacert);

  EXPECT_EQ("localhost", configuration.GetHost());
  EXPECT_EQ(44300, configuration.GetPort());
  auto sslcc = configuration.GetChannelCredentials();
  EXPECT_TRUE(sslcc != nullptr);
}

TEST_F(test_connection, connection_manager_unknown_connection) {
  EXPECT_THROW_MESSAGE(
    ConnectionManager::GetConnection("test"), linkahead::exceptions::ConnectionConfigurationError,
    "Error with the connection named 'test': The connection 'test' has not been defined.");
}

TEST_F(test_connection, connection_missing_certificate) {
  EXPECT_THROW_MESSAGE(ConnectionManager::GetConnection("missing"),
                       linkahead::exceptions::ConnectionConfigurationError,
                       std::string("Error with the connection named 'missing': ") +
                         "File does not exist (server_certificate_path): /missing");
}

TEST_F(test_connection, connection_manager_get_default_connection) {
  auto connection = ConnectionManager::GetDefaultConnection();
  EXPECT_EQ(connection, ConnectionManager::GetConnection("local-linkahead"));
}

TEST_F(test_connection, connection_manager_get_connection) {

  EXPECT_TRUE(ConnectionManager::GetConnection("local-linkahead-admin"));
}

#ifdef BUILD_ACM
TEST_F(test_connection, test_create_single_user) {
  auto connection = ConnectionManager::GetDefaultConnection();
  User user;
  EXPECT_THROW_MESSAGE(connection->CreateSingleUser(user), linkahead::exceptions::ConnectionError,
                       "The attempt to execute this transaction was not successful because the "
                       "connection to the server could not be established.");
}

TEST_F(test_connection, test_delete_single_user) {
  auto connection = ConnectionManager::GetDefaultConnection();
  EXPECT_THROW_MESSAGE(connection->DeleteSingleUser("realm", "user"),
                       linkahead::exceptions::ConnectionError,
                       "The attempt to execute this transaction was not successful because the "
                       "connection to the server could not be established.");
}

TEST_F(test_connection, test_retrieve_single_user) {
  auto connection = ConnectionManager::GetDefaultConnection();
  EXPECT_THROW_MESSAGE(auto results = connection->RetrieveSingleUser("realm", "user"),
                       linkahead::exceptions::ConnectionError,
                       "The attempt to execute this transaction was not successful because the "
                       "connection to the server could not be established.");
}
#endif

} // namespace linkahead::connection