#ifndef _TILE_BASE_RANDOM_H
#define _TILE_BASE_RANDOM_H

#pragma once
#include <cstdint>
#include <random>
#include <type_traits>

namespace tile {
namespace random {
inline std::mt19937_64 &
Engine()
{
    thread_local auto engine = [] {
        std::random_device r;
        std::seed_seq seeds{r(), r(), r(), r(), r(), r(), r(), r()};

        std::mt19937_64 engine(seeds);
        return engine;
    }();

    return engine;
}
}// namespace random

template<typename T = std::uint64_t, typename = typename std::enable_if<std::is_integral<T>::value>::type>
T
Random()
{
    return random::Engine()();
}

template<typename T>
T
Random(T min, T max)
{
    using Distribution = typename std::conditional<std::is_floating_point<T>::value, std::uniform_real_distribution<T>,
                                                   std::uniform_int_distribution<T>>::type;

    Distribution dist(min, max);
    return dist(random::Engine());
}

template<typename T>
T
Random(T max)
{
    return Random<T>(T(0), max);
}

}// namespace tile

#endif// _TILE_BASE_RANDOM_H
