#ifndef TILE_BASE_OPTION_OPTION_PROVIDER_H
#define TILE_BASE_OPTION_OPTION_PROVIDER_H

#pragma once
#include "tile/base/dependency_registry.h"
#include "tile/base/make_unique.h"
#include "tile/base/option/key.h"
#include "tile/base/optional.h"
#include "tile/base/status.h"

namespace tile {
class OptionPassiveProvider {
public:
    virtual ~OptionPassiveProvider()                                                            = default;

    virtual bool GetAll(const std::vector<const option::MultiKey *> &names)                     = 0;

    virtual Status GetBool(const option::MultiKey &name, std::optional<bool> *value)            = 0;
    virtual Status GetInt8(const option::MultiKey &name, std::optional<std::int8_t> *value)     = 0;
    virtual Status GetUInt8(const option::MultiKey &name, std::optional<std::uint8_t> *value)   = 0;
    virtual Status GetInt16(const option::MultiKey &name, std::optional<std::int16_t> *value)   = 0;
    virtual Status GetUInt16(const option::MultiKey &name, std::optional<std::uint16_t> *value) = 0;
    virtual Status GetInt32(const option::MultiKey &name, std::optional<std::int32_t> *value)   = 0;
    virtual Status GetUInt32(const option::MultiKey &name, std::optional<std::uint32_t> *value) = 0;
    virtual Status GetInt64(const option::MultiKey &name, std::optional<std::int64_t> *value)   = 0;
    virtual Status GetUInt64(const option::MultiKey &name, std::optional<std::uint64_t> *value) = 0;
    virtual Status GetFloat(const option::MultiKey &name, std::optional<float> *value)          = 0;
    virtual Status GetDouble(const option::MultiKey &name, std::optional<double> *value)        = 0;
    virtual Status GetString(const option::MultiKey &name, std::optional<std::string> *value)   = 0;

#define TILE_OPTION_NOT_SUPPORTED_IMPL_FOR(ProviderName, Type, TypeName)                                               \
    Status Get##TypeName(const option::MultiKey &name, std::optional<Type> *value) override                            \
    {                                                                                                                  \
        TILE_CHECK(false, "Not supported: provider [{}] does not allow type [{}].", #ProviderName, #TypeName);         \
        return Status(-1);                                                                                             \
    }

};// namespace tile

TILE_DECLARE_OBJECT_DEPENDENCY_REGISTRY(option_passive_provider_registry, OptionPassiveProvider);
#define TILE_OPTION_REGISTER_OPTION_PROVIDER(Name, Implementation)                                                     \
    TILE_REGISTER_OBJECT_DEPENDENCY(::tile::option_passive_provider_registry, Name, [] {                               \
        return ::tile::make_unique<Implementation>();                                                                  \
    })

}// namespace tile

#endif// TILE_BASE_OPTION_OPTION_PROVIDER_H
