#ifndef CORE_ERROR_H
#define CORE_ERROR_H

#include <cstdint>
#include <optional>
#include <string_view>
#include <mutex>
#include <utility>
#include <iostream>
#include <format>

namespace dofs {

void log_error(std::string_view type,
               std::string_view message,
               std::optional<uint64_t> timestamp = std::nullopt) noexcept;

std::mutex &error_mutex() noexcept;

template <class T>
inline T&& show(std::string_view name, T&& value) noexcept {
        std::lock_guard<std::mutex> lock(error_mutex());
        std::cerr << name << '=' << value << '\n';
        return std::forward<T>(value);
}

template <class T>
inline T&& eval_and_show(std::string_view expr, T&& value) noexcept {
        std::lock_guard<std::mutex> lock(error_mutex());
        std::cerr << expr << '=' << value << '\n';
        return std::forward<T>(value);
}

#define DOFS_ERROR(TYPE, MSG) \
        ::dofs::log_error((TYPE), (MSG))

#define DOFS_ERROR_T(TYPE, MSG, TS) \
        ::dofs::log_error((TYPE), (MSG), (TS))

#define DOFS_ERROR_ST(TYPE, SRC, MSG, TS) \
        ::dofs::log_error((TYPE), (SRC), (MSG), (TS))

#define DOFS_SHOW(VAR) \
        (::dofs::show(#VAR, (VAR)))

#define DOFS_EVAL(EXPR) \
        (::dofs::eval_and_show(#EXPR, (EXPR)))

#define FORMAT(VAR) \
        (std::format("{}={}", #VAR, VAR))

} // namespace dofs

#endif // CORE_ERROR_H
