// Copyright (c) 2017, Xiaomi, Inc.  All rights reserved.
// This source code is licensed under the Apache License Version 2.0, which
// can be found in the LICENSE file in the root directory of this source tree.

#pragma once

#include <getopt.h>
#include <thread>
#include <iomanip>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <rocksdb/db.h>
#include <dsn/utility/filesystem.h>
#include <dsn/utility/output_utils.h>
#include <dsn/utility/string_conv.h>
#include <dsn/utility/string_view.h>
#include <dsn/dist/replication/replication_ddl_client.h>
#include <dsn/dist/replication/mutation_log_tool.h>

#include <rrdb/rrdb.code.definition.h>
#include <rrdb/rrdb_types.h>
#include <pegasus/version.h>
#include <pegasus/git_commit.h>
#include <pegasus/error.h>

#include "command_executor.h"
#include "command_utils.h"
#include "command_helper.h"
#include "args.h"

using namespace dsn::replication;
using tp_alignment = ::dsn::utils::table_printer::alignment;
using tp_output_format = ::dsn::utils::table_printer::output_format;

static const char *INDENT = "  ";
struct list_nodes_helper
{
    std::string node_name;
    std::string node_status;
    int primary_count;
    int secondary_count;
    int64_t memused_res_mb;
    int64_t block_cache_bytes;
    int64_t mem_tbl_bytes;
    int64_t mem_idx_bytes;
    int64_t disk_available_total_ratio;
    int64_t disk_available_min_ratio;
    double get_qps;
    double put_qps;
    double multi_get_qps;
    double multi_put_qps;
    double get_p99;
    double put_p99;
    double multi_get_p99;
    double multi_put_p99;
    double read_cu;
    double write_cu;
    list_nodes_helper(const std::string &n, const std::string &s)
        : node_name(n),
          node_status(s),
          primary_count(0),
          secondary_count(0),
          memused_res_mb(0),
          block_cache_bytes(0),
          mem_tbl_bytes(0),
          mem_idx_bytes(0),
          disk_available_total_ratio(0),
          disk_available_min_ratio(0),
          get_qps(0.0),
          put_qps(0.0),
          multi_get_qps(0.0),
          multi_put_qps(0.0),
          get_p99(0.0),
          put_p99(0.0),
          multi_get_p99(0.0),
          multi_put_p99(0.0),
          read_cu(0.0),
          write_cu(0.0)
    {
    }
};

// == miscellaneous (see 'commands/misc.cpp') == //

bool help_info(command_executor *e, shell_context *sc, arguments args);

bool version(command_executor *e, shell_context *sc, arguments args);

bool exit_shell(command_executor *e, shell_context *sc, arguments args);

// == global properties (see 'commands/global_properties.cpp') == //

bool use_app_as_current(command_executor *e, shell_context *sc, arguments args);

bool process_escape_all(command_executor *e, shell_context *sc, arguments args);

bool process_timeout(command_executor *e, shell_context *sc, arguments args);

bool cc_command(command_executor *e, shell_context *sc, arguments args);

// == node management (see 'commands/node_management.cpp') == //

bool query_cluster_info(command_executor *e, shell_context *sc, arguments args);

bool ls_nodes(command_executor *e, shell_context *sc, arguments args);

bool server_info(command_executor *e, shell_context *sc, arguments args);

bool server_stat(command_executor *e, shell_context *sc, arguments args);

bool remote_command(command_executor *e, shell_context *sc, arguments args);

bool flush_log(command_executor *e, shell_context *sc, arguments args);

// == table management (see 'commands/table_management.cpp') == //

bool ls_apps(command_executor *e, shell_context *sc, arguments args);

bool query_app(command_executor *e, shell_context *sc, arguments args);

bool app_disk(command_executor *e, shell_context *sc, arguments args);

bool app_stat(command_executor *e, shell_context *sc, arguments args);

bool create_app(command_executor *e, shell_context *sc, arguments args);

bool drop_app(command_executor *e, shell_context *sc, arguments args);

bool recall_app(command_executor *e, shell_context *sc, arguments args);

bool get_app_envs(command_executor *e, shell_context *sc, arguments args);

bool set_app_envs(command_executor *e, shell_context *sc, arguments args);

bool del_app_envs(command_executor *e, shell_context *sc, arguments args);

bool clear_app_envs(command_executor *e, shell_context *sc, arguments args);

// == data operations (see 'commands/data_operations.cpp') == //

bool data_operations(command_executor *e, shell_context *sc, arguments args);

bool set_value(command_executor *e, shell_context *sc, arguments args);

bool multi_set_value(command_executor *e, shell_context *sc, arguments args);

bool get_value(command_executor *e, shell_context *sc, arguments args);

bool multi_get_value(command_executor *e, shell_context *sc, arguments args);

bool multi_get_range(command_executor *e, shell_context *sc, arguments args);

bool multi_get_sortkeys(command_executor *e, shell_context *sc, arguments args);

bool delete_value(command_executor *e, shell_context *sc, arguments args);

bool multi_del_value(command_executor *e, shell_context *sc, arguments args);

bool multi_del_range(command_executor *e, shell_context *sc, arguments args);

bool incr(command_executor *e, shell_context *sc, arguments args);

bool check_and_set(command_executor *e, shell_context *sc, arguments args);

bool check_and_mutate(command_executor *e, shell_context *sc, arguments args);

bool exist(command_executor *e, shell_context *sc, arguments args);

bool sortkey_count(command_executor *e, shell_context *sc, arguments args);

bool get_ttl(command_executor *e, shell_context *sc, arguments args);

bool calculate_hash_value(command_executor *e, shell_context *sc, arguments args);

bool hash_scan(command_executor *e, shell_context *sc, arguments args);

bool full_scan(command_executor *e, shell_context *sc, arguments args);

bool copy_data(command_executor *e, shell_context *sc, arguments args);

bool clear_data(command_executor *e, shell_context *sc, arguments args);

bool count_data(command_executor *e, shell_context *sc, arguments args);

// == load balancing(see 'commands/rebalance.cpp') == //

bool set_meta_level(command_executor *e, shell_context *sc, arguments args);

bool get_meta_level(command_executor *e, shell_context *sc, arguments args);

bool propose(command_executor *e, shell_context *sc, arguments args);

bool balance(command_executor *e, shell_context *sc, arguments args);

// == data recovery(see 'commands/recovery.cpp') == //

bool recover(command_executor *e, shell_context *sc, arguments args);

bool ddd_diagnose(command_executor *e, shell_context *sc, arguments args);

// == cold backup (see 'commands/cold_backup.cpp') == //

bool add_backup_policy(command_executor *e, shell_context *sc, arguments args);

bool ls_backup_policy(command_executor *e, shell_context *sc, arguments args);

bool modify_backup_policy(command_executor *e, shell_context *sc, arguments args);

bool disable_backup_policy(command_executor *e, shell_context *sc, arguments args);

bool enable_backup_policy(command_executor *e, shell_context *sc, arguments args);

bool restore(command_executor *e, shell_context *sc, arguments args);

bool query_backup_policy(command_executor *e, shell_context *sc, arguments args);

bool query_restore_status(command_executor *e, shell_context *sc, arguments args);

// == debugger (see 'commands/debugger.cpp') == //Debugging tool

bool sst_dump(command_executor *e, shell_context *sc, arguments args);

bool mlog_dump(command_executor *e, shell_context *sc, arguments args);

bool local_get(command_executor *e, shell_context *sc, arguments args);

bool rdb_key_hex2str(command_executor *e, shell_context *sc, arguments args);

bool rdb_key_str2hex(command_executor *e, shell_context *sc, arguments args);

bool rdb_value_hex2str(command_executor *e, shell_context *sc, arguments args);

// == duplication (see 'commands/duplication.cpp') == //

bool add_dup(command_executor *e, shell_context *sc, arguments args);

bool query_dup(command_executor *e, shell_context *sc, arguments args);

bool remove_dup(command_executor *e, shell_context *sc, arguments args);

bool start_dup(command_executor *e, shell_context *sc, arguments args);

bool pause_dup(command_executor *e, shell_context *sc, arguments args);

bool set_dup_fail_mode(command_executor *e, shell_context *sc, arguments args);

// == disk rebalance (see 'commands/disk_rebalance.cpp') == //

bool query_disk_capacity(command_executor *e, shell_context *sc, arguments args);

bool query_disk_replica(command_executor *e, shell_context *sc, arguments args);
