// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "env.h"

#include <algorithm>
#include <memory>
#include <string>

#include <fmt/core.h>
#include <rocksdb/convenience.h>
#include <rocksdb/env.h>
#include <rocksdb/env_encryption.h>
#include <rocksdb/slice.h>

#include "utils/defer.h"
#include "utils/filesystem.h"
#include "utils/flags.h"
#include "utils/fmt_logging.h"
#include "utils/utils.h"

DSN_DEFINE_bool(pegasus.server,
                encrypt_data_at_rest,
                false,
                "Whether the sensitive files should be encrypted on the file system.");

DSN_DEFINE_string(pegasus.server,
                  server_key,
                  "0123456789ABCDEF0123456789ABCDEF",
                  "The encrypted server key to use in the filesystem.");

DSN_DEFINE_string(pegasus.server,
                  encryption_method,
                  "AES128CTR",
                  "The encryption method to use in the filesystem. Now "
                  "supports AES128CTR, AES192CTR, AES256CTR and SM4CTR.");

DSN_DEFINE_bool(replication,
                enable_direct_io,
                false,
                "Whether to enable direct I/O when download files");
DSN_TAG_VARIABLE(enable_direct_io, FT_MUTABLE);

namespace dsn {
namespace utils {

rocksdb::Env *NewEncryptedEnv()
{
    // Create an encryption provider.
    std::shared_ptr<rocksdb::EncryptionProvider> provider;
    const auto &provider_id = fmt::format(
        "id=AES;hex_instance_key={};method={}", FLAGS_server_key, FLAGS_encryption_method);
    const auto &s = rocksdb::EncryptionProvider::CreateFromString(
        rocksdb::ConfigOptions(), provider_id, &provider);
    CHECK(s.ok(), "Failed to create encryption provider: {}", s.ToString());

    // Create an encrypted env.
    return NewEncryptedEnv(rocksdb::Env::Default(), provider);
}

rocksdb::Env *PegasusEnv(FileDataType type)
{
    // Return an encrypted env only when the file is sensitive and FLAGS_encrypt_data_at_rest
    // is enabled at the same time.
    if (FLAGS_encrypt_data_at_rest && type == FileDataType::kSensitive) {
        static rocksdb::Env *env = NewEncryptedEnv();
        return env;
    }

    // Otherwise, return a common non-encrypted env.
    static rocksdb::Env *env = rocksdb::Env::Default();
    return env;
}

namespace {
rocksdb::Status do_copy_file(const std::string &src_fname,
                             dsn::utils::FileDataType src_type,
                             const std::string &dst_fname,
                             dsn::utils::FileDataType dst_type,
                             int64_t remain_size,
                             uint64_t *total_size)
{
    rocksdb::EnvOptions src_env_options;
    src_env_options.use_direct_reads = FLAGS_enable_direct_io;
    std::unique_ptr<rocksdb::SequentialFile> src_file;
    auto s =
        dsn::utils::PegasusEnv(src_type)->NewSequentialFile(src_fname, &src_file, src_env_options);
    LOG_AND_RETURN_NOT_RDB_OK(WARNING, s, "failed to open file {} for reading", src_fname);

    // Limit the size of the file to be copied.
    int64_t src_file_size;
    CHECK_TRUE(dsn::utils::filesystem::file_size(src_fname, src_type, src_file_size));
    if (remain_size == -1) {
        // Copy the whole file if 'remain_size' is -1.
        remain_size = src_file_size;
    } else {
        remain_size = std::min(remain_size, src_file_size);
    }

    rocksdb::EnvOptions dst_env_options;
    dst_env_options.use_direct_writes = FLAGS_enable_direct_io;
    std::unique_ptr<rocksdb::WritableFile> dst_file;
    s = dsn::utils::PegasusEnv(dst_type)->NewWritableFile(dst_fname, &dst_file, dst_env_options);
    LOG_AND_RETURN_NOT_RDB_OK(WARNING, s, "failed to open file {} for writing", dst_fname);

    // Read at most 4MB once.
    // TODO(yingchun): make it configurable.
    const uint64_t kCopyBlockSize = 4 << 20;
    auto buffer = dsn::utils::make_shared_array<char>(kCopyBlockSize);
    uint64_t offset = 0;
    do {
        int bytes_per_copy = std::min(remain_size, static_cast<int64_t>(kCopyBlockSize));
        // Reach the EOF.
        if (bytes_per_copy <= 0) {
            break;
        }

        rocksdb::Slice result;
        LOG_AND_RETURN_NOT_RDB_OK(WARNING,
                                  src_file->Read(bytes_per_copy, &result, buffer.get()),
                                  "failed to read file {}",
                                  src_fname);
        CHECK(!result.empty(),
              "read file {} at offset {} with size {} failed",
              src_fname,
              offset,
              bytes_per_copy);
        LOG_AND_RETURN_NOT_RDB_OK(
            WARNING, dst_file->Append(result), "failed to write file {}", dst_fname);

        offset += result.size();
        remain_size -= result.size();

        // Reach the EOF.
        if (result.size() < bytes_per_copy) {
            break;
        }
    } while (true);
    LOG_AND_RETURN_NOT_RDB_OK(WARNING, dst_file->Fsync(), "failed to fsync file {}", dst_fname);

    if (total_size != nullptr) {
        *total_size = offset;
    }

    LOG_INFO("copy file from {} to {}, total size {}", src_fname, dst_fname, offset);
    return rocksdb::Status::OK();
}
} // anonymous namespace

rocksdb::Status
copy_file(const std::string &src_fname, const std::string &dst_fname, uint64_t *total_size)
{
    // TODO(yingchun): Consider to use hard link, i.e. rocksdb::Env()::LinkFile().
    return do_copy_file(
        src_fname, FileDataType::kSensitive, dst_fname, FileDataType::kSensitive, -1, total_size);
}

rocksdb::Status
encrypt_file(const std::string &src_fname, const std::string &dst_fname, uint64_t *total_size)
{
    return do_copy_file(src_fname,
                        FileDataType::kNonSensitive,
                        dst_fname,
                        FileDataType::kSensitive,
                        -1,
                        total_size);
}

rocksdb::Status encrypt_file(const std::string &fname, uint64_t *total_size)
{
    // TODO(yingchun): add timestamp to the tmp encrypted file name.
    std::string tmp_fname = fname + ".encrypted.tmp";
    auto cleanup = dsn::defer([tmp_fname]() { utils::filesystem::remove_path(tmp_fname); });
    LOG_AND_RETURN_NOT_RDB_OK(
        WARNING, encrypt_file(fname, tmp_fname, total_size), "failed to encrypt file {}", fname);
    if (!::dsn::utils::filesystem::rename_path(tmp_fname, fname)) {
        LOG_WARNING("rename file from {} to {} failed", tmp_fname, fname);
        return rocksdb::Status::IOError("rename file failed");
    }
    return rocksdb::Status::OK();
}

rocksdb::Status
copy_file_by_size(const std::string &src_fname, const std::string &dst_fname, int64_t limit_size)
{
    return do_copy_file(src_fname,
                        FileDataType::kSensitive,
                        dst_fname,
                        FileDataType::kSensitive,
                        limit_size,
                        nullptr);
}

} // namespace utils
} // namespace dsn
