/*
 * 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 "paimon/rest/rest_api.h"

#include <memory>
#include <string>
#include <utility>

#include "fmt/format.h"
#include "paimon/catalog_options.h"
#include "paimon/common/utils/rapidjson_util.h"
#include "paimon/common/utils/sensitive_config_utils.h"
#include "paimon/logging.h"
#include "paimon/rest/rest_util.h"

namespace paimon {

namespace {
// The `PAIMON_ASSIGN_OR_RAISE` macro cannot take a declaration type containing a comma.
using StringMap = std::map<std::string, std::string>;

// A successful response body may carry credentials (e.g. a token response), so neither it
// nor the parse failure quoting it is echoed into the error message; only the request path
// is reported.
template <typename ResponseT>
Status ParseResponseBody(const std::string& body, const std::string& path, ResponseT* entity) {
    if (!RapidJsonUtil::FromJsonString(body, entity).ok()) {
        return Status::Invalid(
            fmt::format("failed to deserialize the response of {} from the rest server", path));
    }
    return Status::OK();
}
}  // namespace

RestApi::RestApi(std::unique_ptr<RestHttpClient> client,
                 std::unique_ptr<AuthProvider> auth_provider,
                 const std::map<std::string, std::string>& base_headers,
                 const std::map<std::string, std::string>& options, const ResourcePaths& paths)
    : client_(std::move(client)),
      auth_provider_(std::move(auth_provider)),
      base_headers_(base_headers),
      options_(options),
      resource_paths_(paths) {}

Result<std::unique_ptr<RestApi>> RestApi::Create(const std::map<std::string, std::string>& options,
                                                 const std::string& warehouse, bool config_required,
                                                 const RestHttpClient::Config& http_config) {
    auto uri_iter = options.find(CatalogOptions::URI);
    if (uri_iter == options.end() || uri_iter->second.empty()) {
        return Status::Invalid(fmt::format("option '{}' must be configured for the rest catalog",
                                           CatalogOptions::URI));
    }
    PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<RestHttpClient> client,
                           RestHttpClient::Create(uri_iter->second, http_config));
    PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<AuthProvider> auth_provider,
                           AuthProvider::Create(options));

    std::map<std::string, std::string> merged_options = options;
    std::map<std::string, std::string> base_headers =
        RestUtil::ExtractPrefixMap(options, kHeaderOptionPrefix);
    if (config_required) {
        std::map<std::string, std::string> query_params;
        if (!warehouse.empty()) {
            query_params[kQueryParamWarehouse] = warehouse;
        }
        RestAuthParameter auth_parameter =
            RestAuthParameter::Create("GET", ResourcePaths::Config(), query_params, "");
        PAIMON_ASSIGN_OR_RAISE(StringMap headers,
                               auth_provider->MergeAuthHeader(base_headers, auth_parameter));
        bool follow_redirects = auth_provider->AllowsRedirects();
        PAIMON_ASSIGN_OR_RAISE(RestHttpClient::Response response,
                               client->Execute("GET", ResourcePaths::Config(), query_params,
                                               headers, "", follow_redirects));
        if (!response.IsSuccessful()) {
            return ErrorToStatus(response, follow_redirects);
        }
        ConfigResponse config;
        PAIMON_RETURN_NOT_OK(ParseResponseBody(response.body, ResourcePaths::Config(), &config));
        merged_options = config.Merge(options);
        for (const auto& [key, value] :
             RestUtil::ExtractPrefixMap(merged_options, kHeaderOptionPrefix)) {
            base_headers[key] = value;
        }
        std::shared_ptr<Logger> logger = Logger::GetLogger("RestApi");
        PAIMON_LOG_DEBUG(logger,
                         "merged %zu client options with the /v1/config response into %zu options",
                         options.size(), merged_options.size());
    }
    std::string prefix;
    auto prefix_iter = merged_options.find(kOptionUrlPrefix);
    if (prefix_iter != merged_options.end()) {
        prefix = prefix_iter->second;
    }
    return std::unique_ptr<RestApi>(new RestApi(std::move(client), std::move(auth_provider),
                                                base_headers, merged_options,
                                                ResourcePaths(prefix)));
}

Status RestApi::ErrorToStatus(const RestHttpClient::Response& response, bool follow_redirects) {
    if (!follow_redirects && response.code >= 300 && response.code < HttpStatus::kBadRequest) {
        std::string message = fmt::format(
            "rest endpoint returned redirect status {}, which is not followed for "
            "signed requests",
            response.code);
        std::string request_id = RestUtil::ExtractRequestId(response.headers);
        if (request_id != RestUtil::kUnknownRequestId) {
            message += fmt::format(" requestId:{}", request_id);
        }
        return Status::IOError(message).WithDetail(
            std::make_shared<RestErrorDetail>(response.code));
    }
    // The code of the parsed error body takes precedence over the http status, which
    // a gateway may have rewritten.
    int64_t code = response.code;
    std::string message;
    std::string resource_info;
    bool body_parsed = false;
    if (!response.body.empty()) {
        ErrorResponse error;
        if (RapidJsonUtil::FromJsonString(response.body, &error).ok()) {
            body_parsed = true;
            // The message may embed secrets (e.g. "password=..."), so it is redacted.
            message = SensitiveConfigUtils::RedactText(error.GetMessage());
            if (!error.GetResourceType().empty()) {
                resource_info = fmt::format(" (resource type: {}, resource name: {})",
                                            error.GetResourceType(), error.GetResourceName());
            }
            if (error.GetCode() != 0) {
                code = error.GetCode();
            }
        }
    }
    if (message.empty()) {
        // The body is never echoed (it may carry credentials), so a server answering with
        // something other than an error object is told apart by the message alone.
        message = body_parsed ? fmt::format("empty error message (http status {})", response.code)
                              : fmt::format("unparsable error response body (http status {})",
                                            response.code);
    }
    message += resource_info;
    std::string request_id = RestUtil::ExtractRequestId(response.headers);
    if (request_id != RestUtil::kUnknownRequestId) {
        message += fmt::format(" requestId:{}", request_id);
    }
    Status status;
    switch (code) {
        case HttpStatus::kBadRequest:
            status = Status::Invalid(message);
            break;
        case HttpStatus::kUnauthorized:
            status = Status::IOError("not authorized: ", message);
            break;
        case HttpStatus::kForbidden:
            status = Status::IOError("forbidden: ", message);
            break;
        case HttpStatus::kNotFound:
            status = Status::NotExist(message);
            break;
        case HttpStatus::kConflict:
            status = Status::Exist(message);
            break;
        case HttpStatus::kInternalServerError:
            status = Status::IOError("server error: ", message);
            break;
        case HttpStatus::kNotImplemented:
            status = Status::NotImplemented(message);
            break;
        case HttpStatus::kServiceUnavailable:
            status = Status::IOError("service unavailable: ", message);
            break;
        default:
            status =
                Status::IOError(fmt::format("rest request failed with code {}: {}", code, message));
            break;
    }
    return status.WithDetail(std::make_shared<RestErrorDetail>(code));
}

Result<RestHttpClient::Response> RestApi::Execute(
    const std::string& method, const std::string& path,
    const std::map<std::string, std::string>& query_params, const std::string& body) const {
    RestAuthParameter auth_parameter = RestAuthParameter::Create(method, path, query_params, body);
    StringMap request_headers = base_headers_;
    if (!body.empty()) {
        // Set before merging the auth headers so a provider that signs headers covers it.
        request_headers["Content-Type"] = "application/json";
    }
    PAIMON_ASSIGN_OR_RAISE(StringMap headers,
                           auth_provider_->MergeAuthHeader(request_headers, auth_parameter));
    bool follow_redirects = auth_provider_->AllowsRedirects();
    PAIMON_ASSIGN_OR_RAISE(
        RestHttpClient::Response response,
        client_->Execute(method, path, query_params, headers, body, follow_redirects));
    if (!response.IsSuccessful()) {
        return ErrorToStatus(response, follow_redirects);
    }
    return response;
}

template <typename ResponseT>
Result<ResponseT> RestApi::GetEntity(const std::string& path,
                                     const std::map<std::string, std::string>& query_params) const {
    PAIMON_ASSIGN_OR_RAISE(RestHttpClient::Response response,
                           Execute("GET", path, query_params, ""));
    ResponseT entity;
    PAIMON_RETURN_NOT_OK(ParseResponseBody(response.body, path, &entity));
    return entity;
}

template <typename ResponseT>
Result<std::vector<typename ResponseT::ItemType>> RestApi::ListAllPages(
    const std::string& path) const {
    std::vector<typename ResponseT::ItemType> items;
    std::map<std::string, std::string> query_params;
    while (true) {
        PAIMON_ASSIGN_OR_RAISE(ResponseT response, GetEntity<ResponseT>(path, query_params));
        const auto& data = response.Data();
        items.insert(items.end(), data.begin(), data.end());
        const std::optional<std::string>& next_page_token = response.NextPageToken();
        if (!next_page_token || next_page_token.value().empty() || data.empty()) {
            return items;
        }
        query_params[kQueryParamPageToken] = next_page_token.value();
    }
}

Result<std::vector<std::string>> RestApi::ListDatabases() const {
    return ListAllPages<ListDatabasesResponse>(resource_paths_.Databases());
}

Status RestApi::CreateDatabase(const std::string& name,
                               const std::map<std::string, std::string>& options) const {
    CreateDatabaseRequest request(name, options);
    PAIMON_ASSIGN_OR_RAISE(std::string body, request.ToJsonString());
    return Execute("POST", resource_paths_.Databases(), {}, body).status();
}

Result<GetDatabaseResponse> RestApi::GetDatabase(const std::string& name) const {
    return GetEntity<GetDatabaseResponse>(resource_paths_.Database(name), {});
}

Status RestApi::DropDatabase(const std::string& name) const {
    return Execute("DELETE", resource_paths_.Database(name), {}, "").status();
}

Result<std::vector<std::string>> RestApi::ListTables(const std::string& database_name) const {
    return ListAllPages<ListTablesResponse>(resource_paths_.Tables(database_name));
}

Result<GetTableResponse> RestApi::GetTable(const Identifier& identifier) const {
    return GetEntity<GetTableResponse>(
        resource_paths_.Table(identifier.GetDatabaseName(), identifier.GetTableName()), {});
}

Status RestApi::CreateTable(const Identifier& identifier, const std::string& schema_json) const {
    CreateTableRequest request(identifier.GetDatabaseName(), identifier.GetTableName(),
                               schema_json);
    PAIMON_ASSIGN_OR_RAISE(std::string body, request.ToJsonString());
    return Execute("POST", resource_paths_.Tables(identifier.GetDatabaseName()), {}, body).status();
}

Status RestApi::DropTable(const Identifier& identifier) const {
    return Execute("DELETE",
                   resource_paths_.Table(identifier.GetDatabaseName(), identifier.GetTableName()),
                   {}, "")
        .status();
}

Status RestApi::RenameTable(const Identifier& from_table, const Identifier& to_table) const {
    RenameTableRequest request(from_table.GetDatabaseName(), from_table.GetTableName(),
                               to_table.GetDatabaseName(), to_table.GetTableName());
    PAIMON_ASSIGN_OR_RAISE(std::string body, request.ToJsonString());
    return Execute("POST", resource_paths_.RenameTable(), {}, body).status();
}

Result<std::vector<Snapshot>> RestApi::ListSnapshots(const Identifier& identifier) const {
    return ListAllPages<ListSnapshotsResponse>(
        resource_paths_.Snapshots(identifier.GetDatabaseName(), identifier.GetTableName()));
}

}  // namespace paimon
