/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include "Base/Wrapper.hpp"
#include "Scene/Drawable.hpp"
#include "Scene/Shader/Shader.hpp"
#include "Scene/Texture.hpp"
#include "Scene/UniformBuffer.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/BillboardControlBlock.hpp"
#include "Math/AABB.hpp"
#include "Scene/TextDrawable.hpp"
#include <list>

namespace OpenVulkano::Scene
{

	struct LabelDrawableSettings
	{
		Math::Vector4f backgroundColor = { 1, 0, 0, 1 };
		float horizontalOffset = 0.05f;
		float verticalOffset = 0.05f;
		float cornerRadius = 0.05f;
		float arrowLength = 0.5f;
		float arrowWidth = 0.2f;
		int32_t hasRoundedCorners = false;
		int32_t hasArrow = false;
	};
	
	struct LabelUniformData
	{
		Math::Vector4f textSize = { 0, 0, 0, 0 };
		Math::Vector4f color = { 0, 0, 0, 0 };
		Math::Vector4f bboxCenter = { 0, 0, 0, 0 };
		float cornerRadius = 0.f;
		float arrowLength = 0.f;
		float arrowWidth = 0.f;
		int32_t hasRoundedCorners = false;
		int32_t hasArrow = false;
	};

	class LabelDrawable final : public Drawable
	{
	public:
		LabelDrawable(const std::shared_ptr<AtlasData>& atlasData,
		              const LabelDrawableSettings& settings = LabelDrawableSettings(), bool isBillboard = false);
		void AddText(const std::string& text, const TextConfig& config = TextConfig());
		void SetLabelSettings(const LabelDrawableSettings& settings);
		void SetBillboardSettings(const BillboardControlBlock& settings);
		void SetPosition(const Math::Vector3f& pos) { m_position = pos; }
		std::list<TextDrawable>& GetTexts() { return m_texts; }
		LabelDrawableSettings& GetSettings() { return m_settings; }
		UniformBuffer* GetBillboardBuffer() { return &m_billboardBuffer; }
		UniformBuffer* GetLabelBuffer() { return &m_labelBuffer; }
		BillboardControlBlock& GetBillboardSettings() { return m_billboardSettings; }
		Math::Vector3f& GetPosition() { return m_position; }
		bool IsBillboard() const { return m_isBillboard; }
		const Math::AABB& GetBoundingBox() const { return m_bbox; }
	private:
		void RecalculateBbox(const Math::AABB& other);
		void SetupShaders();
		void SetupBuffers();
	private:
		Shader m_backgroundShader;
		UniformBuffer m_billboardBuffer;
		UniformBuffer m_labelBuffer;
		// list over vector to prevent memory reallocation and crash
		std::list<TextDrawable> m_texts;
		Shader m_textShader;
		LabelDrawableSettings m_settings;
		LabelUniformData m_labelData;
		std::shared_ptr<AtlasData> m_atlasData;
		BillboardControlBlock m_billboardSettings;
		Math::Vector3f m_position = { 0, 0, 0 };
		Math::AABB m_bbox;
		bool m_isBillboard;
	};
}
