#include <psemek/wgpu/queue.hpp>
#include <psemek/wgpu/detail/string_view.hpp>
#include <psemek/wgpu/external/webgpu.h>

namespace psemek::wgpu
{

	void queue::submit(std::vector<command_buffer> const & commands)
	{
		static_assert(sizeof(WGPUCommandBuffer) == sizeof(command_buffer));
		wgpuQueueSubmit((WGPUQueue)get(), commands.size(), (WGPUCommandBuffer*)commands.data());
	}

	void queue::write_buffer(buffer const & buffer, std::uint64_t offset, util::span<char const> data)
	{
		wgpuQueueWriteBuffer((WGPUQueue)get(), (WGPUBuffer)buffer.get(), offset, data.data(), data.size());
	}

	void queue::write_texture(texel_copy_texture_info const & dest, util::span<char const> data, texel_copy_buffer_layout const & data_layout, math::vector<std::uint32_t, 3> const & write_size)
	{
		WGPUTexelCopyTextureInfo texel_copy_texture_info = {};
		texel_copy_texture_info.texture = (WGPUTexture)dest.texture.get();
		texel_copy_texture_info.mipLevel = dest.mip_level;
		texel_copy_texture_info.origin = {dest.origin[0], dest.origin[1], dest.origin[2]};
		texel_copy_texture_info.aspect = (WGPUTextureAspect)dest.aspect;

		WGPUTexelCopyBufferLayout texel_copy_buffer_layout = {};
		texel_copy_buffer_layout.offset = data_layout.offset;
		texel_copy_buffer_layout.bytesPerRow = data_layout.bytes_per_row;
		texel_copy_buffer_layout.rowsPerImage = data_layout.rows_per_image;

		WGPUExtent3D extent = {write_size[0], write_size[1], write_size[2]};

		wgpuQueueWriteTexture((WGPUQueue)get(), &texel_copy_texture_info, data.data(), data.size(), &texel_copy_buffer_layout, &extent);
	}

	void queue::on_submitted_work_done(callback_mode mode, work_done_callback const & callback)
	{
		WGPUQueueWorkDoneCallbackInfo callback_info = {};
		callback_info.mode = (WGPUCallbackMode)mode;
		callback_info.callback = [](WGPUQueueWorkDoneStatus status, void * userdata, void *)
		{
			std::unique_ptr<work_done_callback> callback((work_done_callback*)userdata);
			if (*callback) (*callback)((work_done_status)status);
		};
		callback_info.userdata1 = new work_done_callback(callback);

		wgpuQueueOnSubmittedWorkDone((WGPUQueue)get(), callback_info);
	}

	void queue::set_label(std::string const & label)
	{
		wgpuQueueSetLabel((WGPUQueue)get(), detail::to_string_view(label));
	}

	void queue::reference(void * ptr)
	{
		wgpuQueueAddRef((WGPUQueue)ptr);
	}

	void queue::release(void * ptr)
	{
		wgpuQueueRelease((WGPUQueue)ptr);
	}

}
