#pragma once

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

#include <psemek/gfx/texture.hpp>
#include <psemek/io/stream.hpp>

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

namespace psemek::fonts::inline v1
{

	enum class font_type
	{
		bitmap,
		msdf,
	};

	struct character_range
	{
		char32_t begin;
		char32_t end;
	};

	struct glyph
	{
		math::box<float, 2> position;
		char32_t character;
	};

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

		char32_t unknown_character = '?';

		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 baseline() const { return 0; }

		virtual bool supports_character(char32_t c) const = 0;
		virtual util::span<character_range const> supported_characters() const = 0;

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

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

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

		virtual gfx::texture_2d const & atlas() const = 0;

		virtual float sdf_scale() const { return 0.f; }

		virtual std::optional<math::box<float, 2>> texcoords(char32_t character) const = 0;

		virtual ~font() {}
	};

	std::unique_ptr<font> make_default_monospace_9x12_font();
	std::unique_ptr<font> make_default_9x12_font();
	std::unique_ptr<font> make_default_10x12_bold_font();

	std::unique_ptr<font> make_bitmap_font(io::istream && description, io::istream && texture);
	std::unique_ptr<font> make_msdf_font(io::istream && description, io::istream && texture);

}
