#include "foundation/task_queue.h"

namespace pp::foundation {

TaskQueue::TaskQueue(std::size_t max_entries) noexcept
    : max_entries_(max_entries)
{
}

std::size_t TaskQueue::size() const noexcept
{
    return tasks_.size();
}

bool TaskQueue::empty() const noexcept
{
    return tasks_.empty();
}

std::size_t TaskQueue::max_entries() const noexcept
{
    return max_entries_;
}

Status TaskQueue::push(TaskItem task)
{
    if (max_entries_ == 0U || max_entries_ > max_task_queue_entries) {
        return Status::out_of_range("task queue capacity is outside the configured range");
    }

    if (task.callback == nullptr) {
        return Status::invalid_argument("task callback must not be null");
    }

    if (tasks_.size() >= max_entries_) {
        return Status::out_of_range("task queue is full");
    }

    tasks_.push_back(task);
    return Status::success();
}

Result<TaskItem> TaskQueue::pop() noexcept
{
    if (tasks_.empty()) {
        return Result<TaskItem>::failure(Status::out_of_range("task queue is empty"));
    }

    const auto task = tasks_.front();
    tasks_.pop_front();
    return Result<TaskItem>::success(task);
}

Status TaskQueue::run_next() noexcept
{
    auto task = pop();
    if (!task.ok()) {
        return task.status();
    }

    task.value().callback(task.value().user_data);
    return Status::success();
}

std::size_t TaskQueue::run_all() noexcept
{
    std::size_t count = 0;
    while (!tasks_.empty()) {
        const auto status = run_next();
        if (!status.ok()) {
            break;
        }
        ++count;
    }
    return count;
}

void TaskQueue::clear() noexcept
{
    tasks_.clear();
}

}
