#pragma once

#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <deque>
#include <mutex>

#include <atomic>

namespace softbus::core::threading
{

/// 多生产者多消费者安全队列（互斥 + 条件变量）。
template <typename T>
class MutexQueue
{
public:
    explicit MutexQueue(std::size_t maxDepth = 0)
        : m_maxDepth(maxDepth)
    {
    }

    bool tryPush(T value)
    {
        std::lock_guard<std::mutex> lk(m_mutex);
        if (m_maxDepth > 0 && m_queue.size() >= m_maxDepth) {
            return false;
        }
        m_queue.push_back(std::move(value));
        m_cv.notify_all();
        return true;
    }

    void push(T value)
    {
        std::lock_guard<std::mutex> lk(m_mutex);
        m_queue.push_back(std::move(value));
        m_cv.notify_all();
    }

    /// `running=false` 且队列空时返回 false。
    bool popWait(T& out, const std::atomic<bool>& running)
    {
        std::unique_lock<std::mutex> lk(m_mutex);
        m_cv.wait(lk, [&] { return !m_queue.empty() || !running.load(std::memory_order_acquire); });
        if (m_queue.empty()) {
            return false;
        }
        out = std::move(m_queue.front());
        m_queue.pop_front();
        return true;
    }

    template <class Rep, class Period>
    bool popWaitFor(T& out, const std::atomic<bool>& running, std::chrono::duration<Rep, Period> timeout)
    {
        std::unique_lock<std::mutex> lk(m_mutex);
        if (!m_cv.wait_for(lk, timeout, [&] {
                return !m_queue.empty() || !running.load(std::memory_order_acquire);
            })) {
            return false;
        }
        if (m_queue.empty()) {
            return false;
        }
        out = std::move(m_queue.front());
        m_queue.pop_front();
        return true;
    }

private:
    std::mutex              m_mutex;
    std::condition_variable m_cv;
    std::deque<T>           m_queue;
    std::size_t             m_maxDepth;
};

} // namespace softbus::core::threading
