#ifndef ASSISTANT_H
#define ASSISTANT_H

#include <fstream>
#include <functional>
#include <random>
#include <string>
#include <thread>

#ifdef USE_BOOST
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#else
#include <filesystem>
namespace fs = std::filesystem;
#endif

/**
 * @brief 比较两个文件的内容是否完全相同
 *
 * @param filea 第一个文件路径
 * @param fileb 第二个文件路径
 * @return true 如果文件内容完全相同
 * @return false 如果文件内容不同或无法读取文件
 */
bool is_equal_filecontent(const std::string& filea, const std::string& fileb);
bool random_file(const std::string& file, size_t size);

/**
 * @brief 等待变量的值达到预期值
 *
 * @tparam T 变量类型
 * @tparam Compare 比较器类型
 * @param value 变量的引用
 * @param expected 预期值
 * @param comparator 比较函数 (默认为 std::equal_to)
 * @param timeout_ms 超时时间(毫秒),0表示无限等待
 * @param interval_ms 检查间隔(毫秒)
 * @return true 变量值符合预期
 * @return false 超时或条件不满足
 */
template <typename T, typename Compare = std::equal_to<T>>
bool value_wait(const std::function<T()>& value_ref, const T& expected, Compare comparator = Compare(),
                unsigned long timeout_ms = 0, unsigned long interval_ms = 100)
{
    auto start = std::chrono::steady_clock::now();

    while (true) {

        T value = value_ref();
        if (comparator(value, expected)) {
            return true;
        }

        if (timeout_ms > 0) {
            auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
                               std::chrono::steady_clock::now() - start)
                               .count();

            if (elapsed >= timeout_ms) {
                return false;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms));
    }
}

class ScopeExit
{
public:
    ScopeExit() = default;
    template <typename F> ScopeExit(F&& f) : func_(std::forward<F>(f))
    {
    }
    ScopeExit(const ScopeExit&) = delete;
    ScopeExit& operator=(const ScopeExit&) = delete;
    ScopeExit(ScopeExit&& other) noexcept : func_(std::move(other.func_))
    {
        other.func_ = nullptr;
    }
    ScopeExit& operator=(ScopeExit&& other) noexcept
    {
        if (this != &other) {
            if (func_)
                func_();
            func_ = std::move(other.func_);
            other.func_ = nullptr;
        }
        return *this;
    }
    ~ScopeExit()
    {
        if (func_)
            func_();
    }
    void dismiss() noexcept
    {
        func_ = nullptr;
    }

private:
    std::function<void()> func_;
};

#define _SCOPE_EXIT_CONCAT(a, b) a##b
#define _MAKE_ON_SCOPE_EXIT(line) ScopeExit _SCOPE_EXIT_CONCAT(exit_defer_, line) = [&]()
#define ON_SCOPE_EXIT _MAKE_ON_SCOPE_EXIT(__LINE__)

#endif   // ASSISTANT_H