/* -*- 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 "couchbase/cas.hxx"

#include "base_error_context.hxx"
#include "key_value_error_map_info.hxx"
#include "key_value_extended_error_info.hxx"
#include "key_value_status_code.hxx"

#include <cstdint>
#include <optional>

namespace couchbase::core
{
/**
 * The error context returned with key/value operations.
 *
 * @since 1.0.0
 * @committed
 */
class key_value_error_context : public core::base_error_context
{
public:
  /**
   * Creates empty error context
   *
   * @since 1.0.0
   * @committed
   */
  key_value_error_context() = default;

  /**
   * Creates and initializes error context with given parameters.
   *
   * @param operation_id
   * @param ec
   * @param last_dispatched_to
   * @param last_dispatched_from
   * @param retry_attempts
   * @param retry_reasons
   * @param id
   * @param bucket
   * @param scope
   * @param collection
   * @param opaque
   * @param status_code
   * @param cas
   * @param error_map_info
   * @param extended_error_info
   *
   * @since 1.0.0
   * @internal
   */
  key_value_error_context(std::string operation_id,
                          std::error_code ec,
                          std::optional<std::string> last_dispatched_to,
                          std::optional<std::string> last_dispatched_from,
                          std::size_t retry_attempts,
                          std::set<retry_reason> retry_reasons,
                          std::string id,
                          std::string bucket,
                          std::string scope,
                          std::string collection,
                          std::uint32_t opaque,
                          std::optional<key_value_status_code> status_code,
                          couchbase::cas cas,
                          std::optional<key_value_error_map_info> error_map_info,
                          std::optional<key_value_extended_error_info> extended_error_info)
    : base_error_context{ std::move(operation_id),
                          ec,
                          std::move(last_dispatched_to),
                          std::move(last_dispatched_from),
                          retry_attempts,
                          std::move(retry_reasons) }
    , id_{ std::move(id) }
    , bucket_{ std::move(bucket) }
    , scope_{ std::move(scope) }
    , collection_{ std::move(collection) }
    , opaque_{ opaque }
    , status_code_{ status_code }
    , cas_{ cas }
    , error_map_info_{ std::move(error_map_info) }
    , extended_error_info_{ std::move(extended_error_info) }
  {
  }

  /**
   * Returns identifier (key) of the document referenced in the operation.
   *
   * @return document identifier
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto id() const -> const std::string&
  {
    return id_;
  }

  /**
   * Returns name of the bucket.
   *
   * @return name of the bucket.
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto bucket() const -> const std::string&
  {
    return bucket_;
  }

  /**
   * Returns name of the scope of the document.
   *
   * @return name of the scope.
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto scope() const -> const std::string&
  {
    return scope_;
  }

  /**
   * Returns name of the collection of the document.
   *
   * @return collection name
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto collection() const -> const std::string&
  {
    return collection_;
  }

  /**
   * Returns opaque number generated by the SDK and repeated by the server.
   *
   * @return opaque number
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto opaque() const -> std::uint32_t
  {
    return opaque_;
  }

  /**
   * Returns status code from the server response.
   *
   * @return protocol status code
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto status_code() const -> const std::optional<key_value_status_code>&
  {
    return status_code_;
  }

  /**
   * Returns CAS value associated with the document on the server.
   *
   * @return CAS value
   *
   * @since 1.0.0
   * @uncommitted
   */
  [[nodiscard]] auto cas() const -> couchbase::cas
  {
    return cas_;
  }

  /**
   * Returns entry from error map, if it was mapped.
   *
   * @return optional error map info
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto error_map_info() const -> const std::optional<key_value_error_map_info>&
  {
    return error_map_info_;
  }

  /**
   * Returns extended error info (if it was rendered in the server response).
   *
   * @return optional error info
   *
   * @since 1.0.0
   * @committed
   */
  [[nodiscard]] auto extended_error_info() const
    -> const std::optional<key_value_extended_error_info>&
  {
    return extended_error_info_;
  }

  [[nodiscard]] auto to_json() const -> std::string;

private:
  std::string id_{};
  std::string bucket_{};
  std::string scope_{};
  std::string collection_{};
  std::uint32_t opaque_{};
  std::optional<key_value_status_code> status_code_{};
  couchbase::cas cas_{};
  std::optional<key_value_error_map_info> error_map_info_{};
  std::optional<key_value_extended_error_info> extended_error_info_{};
};
} // namespace couchbase::core
