#pragma once

#include <psemek/wgpu/detail/object.hpp>
#include <psemek/wgpu/chained_struct.hpp>
#include <psemek/wgpu/compute_pass_encoder.hpp>
#include <psemek/wgpu/render_pass_encoder.hpp>
#include <psemek/wgpu/command_buffer.hpp>
#include <psemek/wgpu/buffer.hpp>
#include <psemek/wgpu/query_set.hpp>
#include <psemek/wgpu/image_copy.hpp>
#include <psemek/math/vector.hpp>

#include <vector>
#include <string>

namespace psemek::wgpu
{

	struct command_encoder
		: detail::object<command_encoder>
	{
		using detail::object<command_encoder>::object;

		struct descriptor
		{
			std::vector<chained_struct> chain = {};
			std::string label = {};
		};

		compute_pass_encoder begin_compute_pass(compute_pass_encoder::descriptor const & desc);
		render_pass_encoder begin_render_pass(render_pass_encoder::descriptor const & desc);
		void clear_buffer(buffer const & buffer, std::uint64_t offset, std::uint64_t size);
		void copy_buffer_to_buffer(buffer const & source, std::uint64_t source_offset, buffer const & destination, std::uint64_t destination_offset, std::uint64_t size);
		void copy_buffer_to_texture(texel_copy_buffer_info const & source, texel_copy_texture_info const & destination, math::vector<std::uint32_t, 3> const & extent);
		void copy_texture_to_buffer(texel_copy_texture_info const & source, texel_copy_buffer_info const & destination, math::vector<std::uint32_t, 3> const & extent);
		void copy_texture_to_texture(texel_copy_texture_info const & source, texel_copy_texture_info const & destination, math::vector<std::uint32_t, 3> const & extent);
		void insert_debug_marker(std::string const & marker_label);
		void push_debug_group(std::string const & group_label);
		void pop_debug_group();
		void resolve_query_set(query_set const & query_set, std::uint32_t first_query, std::uint32_t query_count, buffer const & destination, std::uint64_t destination_offset);
		void write_timestamp(query_set const & query_set, std::uint32_t query_index);
		command_buffer finish(command_buffer::descriptor const & desc);
		void set_label(std::string const & label);

		static void reference(void * ptr);
		static void release(void * ptr);

	private:
		explicit command_encoder(void * ptr)
			: detail::object<command_encoder>(ptr)
		{}

		friend struct device;
	};

}
