/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *   Copyright 2020-Present Couchbase, Inc.
 *
 *   Licensed 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.
 */

#pragma once

#include "core/error_context/http.hxx"
#include "core/operations/management/query_index_build.hxx"
#include "core/operations/management/query_index_get_all_deferred.hxx"
#include "core/operations/operation_traits.hxx"
#include "core/query_context.hxx"
#include "couchbase/management/query_index.hxx"

namespace couchbase::core::operations
{
namespace management
{
struct query_index_build_deferred_response {
  struct query_problem {
    std::uint64_t code{};
    std::string message{};
  };
  error_context::http ctx;
  std::string status{};
  std::vector<query_problem> errors{};
};

struct query_index_build_deferred_request {
  using response_type = query_index_build_deferred_response;
  using encoded_request_type = io::http_request;
  using encoded_response_type = io::http_response;
  using error_context_type = error_context::http;

  static constexpr auto namespace_id = "default";

  std::string bucket_name;
  std::optional<std::string> scope_name;
  std::optional<std::string> collection_name;
  query_context query_ctx;

  std::optional<std::string> client_context_id{};
  std::optional<std::chrono::milliseconds> timeout{};

  [[nodiscard]] response_type make_response(error_context::http&& ctx,
                                            const encoded_response_type& /* encoded */) const
  {
    return { std::move(ctx) };
  }

  static query_index_build_deferred_response convert_response(
    operations::management::query_index_get_all_deferred_response resp)
  {
    return { std::move(resp.ctx), resp.status };
  }

  static query_index_build_deferred_response convert_response(
    operations::management::query_index_build_response resp)
  {
    query_index_build_deferred_response response{ std::move(resp.ctx), resp.status };
    for (const auto& err : resp.errors) {
      query_index_build_deferred_response::query_problem error;
      error.code = err.code;
      error.message = err.message;
      response.errors.emplace_back(error);
    }
    return response;
  }

  template<typename Core, typename Handler>
  void execute(Core core, Handler handler)
  {
    core->execute(query_index_get_all_deferred_request{ bucket_name,
                                                        scope_name.value_or(""),
                                                        collection_name.value_or(""),
                                                        query_ctx,
                                                        client_context_id,
                                                        timeout },
                  [core,
                   handler = std::move(handler),
                   bucket_name = bucket_name,
                   scope_name = scope_name.value_or(""),
                   collection_name = collection_name.value_or(""),
                   query_ctx = query_ctx,
                   client_context_id = client_context_id,
                   timeout = timeout](query_index_get_all_deferred_response resp1) mutable {
                    auto list_resp = std::move(resp1);
                    if (list_resp.ctx.ec || list_resp.index_names.empty()) {
                      return handler(convert_response(std::move(list_resp)));
                    }
                    core->execute(query_index_build_request{ std::move(bucket_name),
                                                             scope_name,
                                                             collection_name,
                                                             query_ctx,
                                                             std::move(list_resp.index_names),
                                                             client_context_id,
                                                             timeout },
                                  [handler = std::move(handler)](
                                    query_index_build_response build_resp) mutable {
                                    return handler(convert_response(std::move(build_resp)));
                                  });
                  });
  }
};
} // namespace management

template<>
struct is_compound_operation<management::query_index_build_deferred_request>
  : public std::true_type {
};

} // namespace couchbase::core::operations