#pragma once

#include <cstddef>
#include <cstdint>
#include <vector>
#include <random>
#include <chrono>
#include <stdexcept>

namespace qkmeans {

// Timer utility for performance measurement
class Timer {
public:
    void start() {
        start_ = std::chrono::high_resolution_clock::now();
    }

    double elapsed_ms() const {
        auto end = std::chrono::high_resolution_clock::now();
        return std::chrono::duration<double, std::milli>(end - start_).count();
    }

private:
    std::chrono::high_resolution_clock::time_point start_;
};

// Memory-aligned allocation for SIMD operations
template<typename T>
inline T* aligned_alloc(size_t n, size_t alignment = 32) {
    void* ptr = nullptr;
#ifdef _WIN32
    ptr = _aligned_malloc(n * sizeof(T), alignment);
#else
    if (posix_memalign(&ptr, alignment, n * sizeof(T)) != 0) {
        ptr = nullptr;
    }
#endif
    if (!ptr) {
        throw std::bad_alloc();
    }
    return static_cast<T*>(ptr);
}

template<typename T>
inline void aligned_free(T* ptr) {
#ifdef _WIN32
    _aligned_free(ptr);
#else
    free(ptr);
#endif
}

// RAII wrapper for aligned memory
template<typename T>
class AlignedVector {
public:
    explicit AlignedVector(size_t n, size_t alignment = 32)
        : data_(aligned_alloc<T>(n, alignment)), size_(n) {}

    ~AlignedVector() {
        if (data_) aligned_free(data_);
    }

    AlignedVector(const AlignedVector&) = delete;
    AlignedVector& operator=(const AlignedVector&) = delete;

    AlignedVector(AlignedVector&& other) noexcept
        : data_(other.data_), size_(other.size_) {
        other.data_ = nullptr;
        other.size_ = 0;
    }

    T* data() { return data_; }
    const T* data() const { return data_; }
    size_t size() const { return size_; }
    T& operator[](size_t i) { return data_[i]; }
    const T& operator[](size_t i) const { return data_[i]; }

private:
    T* data_;
    size_t size_;
};

// Thread-safe random number generator wrapper
class ThreadLocalRNG {
public:
    static std::mt19937_64& get() {
        thread_local std::mt19937_64 rng(std::random_device{}());
        return rng;
    }

    static void seed(uint64_t s) {
        get().seed(s);
    }
};

} // namespace qkmeans
