/* -*- 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 <couchbase/error_context.hxx>
#include <couchbase/key_value_error_map_info.hxx>
#include <couchbase/key_value_extended_error_info.hxx>
#include <couchbase/key_value_status_code.hxx>

#include <cstdint>
#include <optional>

namespace couchbase
{
/**
 * The error context returned with key/value operations.
 *
 * @since 1.0.0
 * @committed
 */
class key_value_error_context : public 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)
      : 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
