#pragma once

#include <psemek/math/vector.hpp>
#include <psemek/math/box.hpp>
#include <psemek/util/span.hpp>

#if defined(PSEMEK_GRAPHICS_API_OPENGL)
#error "Fonts v2 don't support OpenGL yet"
#elif defined(PSEMEK_GRAPHICS_API_WEBGPU)
#include <psemek/wgpu/device.hpp>
#include <psemek/wgpu/texture_view.hpp>
#endif

#include <psemek/io/stream.hpp>

#include <string_view>
#include <vector>
#include <memory>
#include <filesystem>

namespace psemek::fonts
{

	enum class font_type
	{
		bitmap,
		sdf,
		msdf,
	};

#if defined(PSEMEK_GRAPHICS_API_OPENGL)
	// TODO
#elif defined(PSEMEK_GRAPHICS_API_WEBGPU)
	using texture_type = wgpu::texture_view;
#endif

	struct shaped_glyph
	{
		texture_type const * texture;
		math::box<float, 2> position;
		math::box<float, 2> texcoords;
	};

	struct shape_options
	{
		enum direction_t
		{
			left_to_right,
			right_to_left,
			top_to_bottom,
			bottom_to_top,
		} direction = left_to_right;

		float scale = 1.f;
	};

	struct font
	{
		virtual font_type type() const = 0;

		virtual std::string_view name() const = 0;

		virtual math::vector<int, 2> size() const = 0;
		virtual int xheight() const = 0;

		virtual std::vector<shaped_glyph> const & shape(std::string_view str, shape_options const & options, math::point<float, 2> & pen) = 0;
		virtual std::vector<shaped_glyph> const & shape(std::u32string_view str, shape_options const & options, math::point<float, 2> & pen) = 0;

		virtual std::vector<shaped_glyph> const & shape(std::string_view str, shape_options const & options)
		{
			math::point<float, 2> pen{0.f, 0.f};
			return shape(str, options, pen);
		}

		virtual std::vector<shaped_glyph> const & shape(std::u32string_view str, shape_options const & options)
		{
			math::point<float, 2> pen{0.f, 0.f};
			return shape(str, options, pen);
		}

		virtual ~font() {}
	};

	struct font_builder
	{
		virtual std::string_view name() const = 0;

		virtual std::unique_ptr<font> create(font_type type, int size) = 0;

		virtual ~font_builder() {}
	};

	std::unique_ptr<font_builder> load_freetype_font(wgpu::device device, std::filesystem::path const & path);

	// Font paths are specified in order
	std::unique_ptr<font_builder> load_combined_freetype_font(wgpu::device device, std::vector<std::filesystem::path> const & paths);

}
