#include "tile/base/config/json_configuration.h"

#include "gmock/gmock-matchers.h"
#include "gtest/gtest.h"

namespace tile {
namespace {
const char *kJsonConfig = R"(
    {
        "key1": "value1",
        "key2": 2,
        "key3": 3.0,
        "key4": true,
        "key5": {
            "key51": "value51",
            "key52": 52
        }
    }
    )";
}

TEST(JSONConfiguration, Load)
{
    JSONConfiguration config;
    std::istringstream istr(kJsonConfig);
    ASSERT_TRUE(config.load(istr));
}

TEST(JSONConfiguration, Has)
{
    JSONConfiguration config;
    std::istringstream istr(kJsonConfig);
    ASSERT_TRUE(config.load(istr));

    ASSERT_TRUE(config.Has("key1"));
    ASSERT_TRUE(config.Has("key2"));
    ASSERT_TRUE(config.Has("key3"));
    ASSERT_TRUE(config.Has("key4"));
    ASSERT_TRUE(config.Has("key5"));
    ASSERT_TRUE(config.Has("key5.key51"));
    ASSERT_TRUE(config.Has("key5.key52"));
}

TEST(JSONConfiguration, SampleSet)
{
    JSONConfiguration config;
    std::istringstream istr(kJsonConfig);
    ASSERT_TRUE(config.load(istr));
    ASSERT_TRUE(config.GetInt32("key2"));
    ASSERT_EQ(*config.GetInt32("key2"), 2);

    config.SetInt("key2", 20);
    ASSERT_TRUE(config.GetInt32("key2"));
    ASSERT_EQ(20, *config.GetInt32("key2")) << config.Dump();

    config.SetDouble("key3", 30.0);
    ASSERT_TRUE(config.GetDouble("key3"));
    ASSERT_NEAR(30.0, *config.GetDouble("key3"), 0.0001) << config.Dump();

    config.SetBool("key4", false);
    ASSERT_TRUE(config.GetBool("key4"));
    ASSERT_FALSE(*config.GetBool("key4")) << config.Dump();
}

TEST(JSONConfiguration, LayeredSet)
{
    JSONConfiguration config;
    std::istringstream istr(kJsonConfig);
    ASSERT_TRUE(config.load(istr));

    // ASSERT_TRUE(config.GetInt32("key5.key52"));
    config.SetInt("key5.key52", 520);
    ASSERT_TRUE(config.GetInt32("key5.key52")) << config.Dump();
    ASSERT_EQ(520, *config.GetInt32("key5.key52")) << config.Dump();

    // override by other type
    config.SetBool("key5.key52", false);
    ASSERT_TRUE(config.GetBool("key5.key52")) << config.Dump();
    ASSERT_FALSE(*config.GetBool("key5.key52")) << config.Dump();
}

TEST(json_configuration, Enumerate)
{
    JSONConfiguration config;
    std::istringstream istr(kJsonConfig);
    ASSERT_TRUE(config.load(istr));
    auto keys = config.keys("");
    ASSERT_EQ(5, keys.size());
    ASSERT_THAT(keys, ::testing::UnorderedElementsAre("key1", "key2", "key3", "key4", "key5"));

    keys = config.keys("key5");
    ASSERT_EQ(2, keys.size());
    ASSERT_THAT(keys, ::testing::UnorderedElementsAre("key5.key51", "key5.key52"));

    config.Remove("key5.key51");
    keys = config.keys("key5");
    ASSERT_EQ("key5.key52", keys[0]);
}

}// namespace tile
