#pragma once

#include <psemek/app/event_handler.hpp>

#if defined(PSEMEK_GRAPHICS_API_WEBGPU)
#include <psemek/wgpu/instance.hpp>
#include <psemek/wgpu/adapter.hpp>
#include <psemek/wgpu/surface.hpp>
#include <psemek/wgpu/device.hpp>
#endif

#include <memory>
#include <functional>

namespace psemek::app
{

	struct application
		: event_handler
	{
		// Data sent to platform backend for initialization
		struct options
		{
			std::string name;
			int multisampling = 4;
			bool highdpi = false;
#if defined(PSEMEK_GRAPHICS_API_WEBGPU)
			std::vector<wgpu::feature> required_features = {};
			std::optional<wgpu::limits> required_limits = {};
			std::optional<wgpu::native_limits> required_native_limits = {};
#endif
		};

		// Data received from platform backend after initialization
		struct context
		{
			std::vector<std::string> args;
			std::function<void(bool)> show_cursor;
			std::function<void(bool)> relative_mouse_mode;
			std::function<void(bool)> windowed;
			std::function<void(bool)> text_input;
#if defined(PSEMEK_GRAPHICS_API_OPENGL)
			std::function<void(bool)> vsync;
#endif
#if defined(PSEMEK_GRAPHICS_API_WEBGPU)
			wgpu::instance instance;
			wgpu::adapter adapter;
			wgpu::surface surface;
			wgpu::device device;
#endif
		};

		struct factory
		{
			virtual application::options options() = 0;
			virtual std::unique_ptr<application> create(struct application::options const & options, context const & context) = 0;

			virtual ~factory() {}
		};

		virtual bool running() const = 0;
		virtual void stop() = 0;

		virtual void update() = 0;
		virtual void present() = 0;
	};

	// Implemented by the user, called by platform backends
	std::unique_ptr<application::factory> make_application_factory();

}
