#include "thread_pool.h"

ThreadPool::ThreadPool(size_t num_threads) {
    for (size_t i = 0; i < num_threads; ++i) {
        workers_.emplace_back([this] {
            for (;;) {
                std::function<void()> task;
                {
                    std::unique_lock<std::mutex> lock(queue_mutex_);
                    condition_.wait(lock, [this] { return stop_ || !tasks_.empty(); });
                    if (stop_ && tasks_.empty()) return;
                    task = std::move(tasks_.front());
                    tasks_.pop();
                    ++active_tasks_;
                }
                task();
                {
                    std::lock_guard<std::mutex> lock(queue_mutex_);
                    --active_tasks_;
                }
                done_condition_.notify_all();
            }
        });
    }
}

ThreadPool::~ThreadPool() {
    {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        stop_ = true;
    }
    condition_.notify_all();
    for (auto& worker : workers_) {
        worker.join();
    }
}

void ThreadPool::enqueue(std::function<void()> task) {
    {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        tasks_.emplace(std::move(task));
    }
    condition_.notify_one();
}

void ThreadPool::wait_all() {
    std::unique_lock<std::mutex> lock(queue_mutex_);
    // Wait for both queue empty AND all active tasks completed
    done_condition_.wait(lock, [this] { return tasks_.empty() && active_tasks_.load() == 0; });
}

uint32_t ThreadPool::default_thread_count() {
    uint32_t n = std::thread::hardware_concurrency();
    if (n == 0) n = 4;
    return n > 8 ? 8 : n;
}
