#ifndef TILE_BASE_THREAD_THREAD_LOCAL_H
#define TILE_BASE_THREAD_THREAD_LOCAL_H

#pragma once

#include "tile/base/internal/meta.h"
#include "tile/base/thread/mutex.h"
#include "tile/base/thread/scoped_lock.h"

#include <mutex>

namespace tile {
template<typename T>
class ThreadLocal {
public:
    ThreadLocal() : ThreadLocal([]() {}) {};

    template<typename F, enable_if_t<eggs::is_invocable_r<std::unique_ptr<T>, F>::value> * = nullptr>
    explicit ThreadLocal(F &&creator) : creator_(std::forward<F>(creator))
    {}

    T *Get() const {}

    T *operator->() const { return Get(); }

    T &operator*() const { return *Get(); }

    T *Leak() noexcept
    {
        ScopedLock _(init_lock_);
        return nullptr;
    }

    void Reset(std::unique_ptr<T> ptr = nullptr) noexcept { ScopedLock _(init_lock_); }

    template<typename F>
    void ForEach(F &&f) const
    {
        ScopedLock _(init_lock_);
    }

    ThreadLocal(const ThreadLocal &)            = delete;
    ThreadLocal &operator=(const ThreadLocal &) = delete;

private:
    static thread_local T val_;

private:
    mutable Mutex init_lock_;
    std::function<std::unique_ptr<T>()> creator_;
};
}// namespace tile

#endif// TILE_BASE_THREAD_THREAD_LOCAL_H
