#pragma once
#include <span>
#include <spdlog/spdlog.h>

enum class buffer_type {
    vertex,
    index,
    constant,
};

class renderer_buffer {
public:
    explicit renderer_buffer(buffer_type in_type, const int in_element_byte, const int in_size = 1) : size(in_size),
        element_byte(in_element_byte), type(in_type) {
    }

    virtual ~renderer_buffer() = default;

    virtual void* lock() = 0;
    virtual void unlock() = 0;

    template<class T>
    bool set_data(const T& in_data) {
        if (auto data = lock()) {
            memcpy(data, &in_data, sizeof(T));
            unlock();
            return true;
        }
#if DEBUG
        spdlog::error("Failed to set param buffer data");
#endif
        return false;
    }
    template<class T>
    bool set_data(const std::span<const T>& in_data) {
        if (auto data = lock()) {
            memcpy(data, in_data.data(), sizeof(T) * in_data.size());
            unlock();
            return true;
        }
#if DEBUG
        spdlog::error("Failed to set param buffer data");
#endif
        return false;
    }

    void resize(const int new_size) {
        if (new_size == size)
            return;
        if (new_size < 1) {
            return;
        }
        size = new_size;
        on_resize(new_size);
    }
    [[nodiscard]] int get_size() const {
        return size;
    }
    [[nodiscard]] buffer_type get_type() const {
        return type;
    }
    [[nodiscard]] virtual void* get_native_handle() = 0;
protected:
    virtual void on_resize(int new_size) = 0;
    int size;
    const int element_byte;
    const buffer_type type;
};
