/*
 * Copyright (c) 2023, 2026, Oracle and/or its affiliates.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2.0,
 * as published by the Free Software Foundation.
 *
 * This program is designed to work with certain software (including
 * but not limited to OpenSSL) that is licensed under separate terms,
 * as designated in a particular file or component or in included license
 * documentation.  The authors of MySQL hereby grant you an additional
 * permission to link the program and your derivative works with the
 * separately licensed software that they have either included with
 * the program or referenced in the documentation.
 *
 * 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, version 2.0, for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "modules/adminapi/base_cluster.h"
#include "modules/adminapi/common/accounts.h"
#include "modules/adminapi/common/api_options.h"
#include "modules/adminapi/mod_dba_routing_guideline.h"
#include "mysqlshdk/libs/utils/utils_json.h"
#include "scripting/types.h"

namespace mysqlsh {
namespace dba {

shcore::Value Base_cluster::get_member(const std::string &prop) const {
  // Throw an error if the cluster has already been dissolved
  assert_valid(prop);

  if (prop == "name") return shcore::Value(base_impl()->get_name());
  return shcore::Cpp_object_bridge::get_member(prop);
}

std::string &Base_cluster::append_descr(
    std::string &s_out, [[maybe_unused]] int indent,
    [[maybe_unused]] int quote_strings) const {
  s_out.append("<")
      .append(class_name())
      .append(+":")
      .append(base_impl()->get_name())
      .append(">");
  return s_out;
}

void Base_cluster::append_json(shcore::JSON_dumper &dumper) const {
  dumper.start_object();
  dumper.append_string("class", class_name());
  dumper.append_string("name", base_impl()->get_name());
  dumper.end_object();
}

bool Base_cluster::operator==(const Object_bridge &other) const {
  return class_name() == other.class_name() && this == &other;
}

shcore::Dictionary_t Base_cluster::list_routers(
    const List_routers_options &options) {
  // Throw an error if the cluster has already been dissolved
  assert_valid("listRouters");

  auto ret_val = execute_with_pool(
      [&]() {
        return base_impl()->list_routers(options.only_upgrade_required);
      },
      false);

  return ret_val.as_map();
}

void Base_cluster::setup_admin_account(const std::string &user,
                                       const Setup_account_options &options) {
  // Throw an error if the cluster has already been dissolved
  assert_valid("setupAdminAccount");

  // split user into user/host
  std::string username, host;
  std::tie(username, host) = validate_account_name(user);

  return execute_with_pool(
      [&]() { base_impl()->setup_admin_account(username, host, options); },
      false);
}

void Base_cluster::setup_router_account(const std::string &user,
                                        const Setup_account_options &options) {
  // Throw an error if the cluster has already been dissolved
  assert_valid("setupRouterAccount");

  // split user into user/host
  std::string username, host;
  std::tie(username, host) = validate_account_name(user);

  return execute_with_pool(
      [&]() { base_impl()->setup_router_account(username, host, options); },
      false);
}

void Base_cluster::set_routing_option(const std::string &option,
                                      const shcore::Value &value) {
  assert_valid("setRoutingOption");

  return execute_with_pool(
      [&]() { base_impl()->set_routing_option("", option, value); }, false);
}

void Base_cluster::set_routing_option(const std::string &router,
                                      const std::string &option,
                                      const shcore::Value &value) {
  assert_valid("setRoutingOption");

  return execute_with_pool(
      [&]() { base_impl()->set_routing_option(router, option, value); }, false);
}

shcore::Dictionary_t Base_cluster::router_options(
    const Router_options_options &options) {
  assert_valid("routerOptions");

  return execute_with_pool(
      [&]() { return base_impl()->router_options(options); }, false);
}

shcore::Value Base_cluster::execute(const std::string &cmd,
                                    const shcore::Value &instances,
                                    const Execute_options &options) {
  assert_valid("execute");

  return execute_with_pool(
      [&]() { return base_impl()->execute(cmd, instances, options); }, false);
}

std::shared_ptr<RoutingGuideline> Base_cluster::create_routing_guideline(
    const std::string &name, shcore::Dictionary_t json,
    const Create_routing_guideline_options &options) {
  assert_valid("createRoutingGuideline");

  return execute_with_pool(
      [&]() -> std::shared_ptr<RoutingGuideline> {
        auto rg = base_impl()->create_routing_guideline(base_impl(), name, json,
                                                        options);

        return std::make_shared<RoutingGuideline>(rg);
      },
      false);
}

std::shared_ptr<RoutingGuideline> Base_cluster::get_routing_guideline(
    const std::string &name) const {
  assert_valid("getRoutingGuideline");

  return execute_with_pool(
      [&]() {
        return std::make_shared<RoutingGuideline>(
            base_impl()->get_routing_guideline(base_impl(), name));
      },
      false);
}

void Base_cluster::remove_routing_guideline(const std::string &name) {
  assert_valid("removeRoutingGuideline");

  return execute_with_pool(
      [&]() { base_impl()->remove_routing_guideline(name); }, false);
}

std::shared_ptr<ShellResult> Base_cluster::routing_guidelines() const {
  assert_valid("routingGuidelines");

  return execute_with_pool(
      [&]() {
        return std::make_shared<ShellResult>(
            base_impl()->routing_guidelines(base_impl()));
      },
      false);
}

std::shared_ptr<RoutingGuideline> Base_cluster::import_routing_guideline(
    const std::string &file_path,
    const Import_routing_guideline_options &options) {
  assert_valid("importRoutingGuideline");

  return execute_with_pool(
      [&]() -> std::shared_ptr<RoutingGuideline> {
        auto rg = base_impl()->import_routing_guideline(base_impl(), file_path,
                                                        options);

        return std::make_shared<RoutingGuideline>(rg);
      },
      false);
}

void Base_cluster::reset_replication_accounts_password(
    const Reset_replication_accounts_password_options &options) {
  assert_valid("resetReplicationAccountsPassword");

  return execute_with_pool(
      [&]() { base_impl()->reset_replication_accounts_password(options); },
      false);
}

}  // namespace dba
}  // namespace mysqlsh
