#pragma once
#include "misc/invalidate_reason.h"
#include "widget_tree/hit_test_result.h"
#include "render/mirage_paint_context.h"
#include "misc/key_type/key_type.h"

class mwindow;

/**
 * @class mwidget
 * @brief UI组件包装器
 *
 * 对widget entity的封装，提供了组件的基本功能。
 */
class mwidget : public std::enable_shared_from_this<mwidget> {
public:
	virtual ~mwidget();
	virtual const mwindow* get_window() const;
	virtual mwindow* get_window();

	virtual void init() {}

	virtual void on_paint(mirage_paint_context& in_context) = 0;

	void set_geometry(const geometry_t& in_geometry);
	const auto& get_geometry() const { return geometry_; }

	virtual auto compute_desired_size(float in_layout_scale_multiplier) const -> Eigen::Vector2f = 0;
	void         cache_desired_size(float in_layout_scale_multiplier, bool in_force = false);
	const auto&  get_desired_size() const { return desired_size_; }
	virtual void arrange_children(const geometry_t& in_allotted_geometry) = 0;

	virtual auto get_dpi_scale() const -> float;

	auto get_parent() const { return parent_.lock(); }
	const auto& get_children() const { return children_; }
	void set_parent(const std::shared_ptr<mwidget>& in_parent);
	void remove_from_parent();

	void add_child(const std::shared_ptr<mwidget>& in_child);
	void remove_child(const std::shared_ptr<mwidget>& in_child);

	virtual void invalidate(invalidate_reason in_reason);
	auto has_invalidate_reason(invalidate_reason in_reason) const { return has_any_flag(invalidate_, in_reason); }
	void set_invalidate_reason(invalidate_reason in_reason) { set_flag(invalidate_, in_reason); }
	void unset_invalid_reason(invalidate_reason in_reason) { clear_flag(invalidate_, in_reason); }
	auto get_invalidation_reason() const { return invalidate_; }

	auto is_enabled() const { return enabled_; }
	void set_enabled(bool in_enabled) { enabled_ = in_enabled; }
	auto get_visibility() const { return visibility_; }
	void set_visibility(visibility_t in_visibility) { visibility_ = in_visibility; }

	bool can_hit_test() const;

	//-------------- 鼠标事件处理 --------------

	/**
	 * @brief 处理鼠标进入事件
	 * @result 命中测试结果
	 */
	virtual void on_mouse_enter() {}

	/**
	 * @brief 处理鼠标离开事件
	 * @result 命中测试结果
	 */
	virtual void on_mouse_leave() {}

	/**
	 * @brief 处理鼠标移动事件
	 * @param in_position 本地坐标系中的鼠标位置
	 * @result 命中测试结果
	 */
	virtual hit_test_handle on_mouse_move(const Eigen::Vector2f& in_position) { return hit_test_handle::unhandled(); }

	/**
	 * @brief 处理鼠标按下事件
	 * @param in_position 本地坐标系中的鼠标位置
	 * @param in_button 按下的鼠标按钮
	 * @result 命中测试结果
	 */
	virtual hit_test_handle on_mouse_button_down(const Eigen::Vector2f& in_position, mouse_button in_button) { return hit_test_handle::unhandled(); }

	/**
	 * @brief 处理鼠标释放事件
	 * @param in_position 本地坐标系中的鼠标位置
	 * @param in_button 释放的鼠标按钮
	 * @result 命中测试结果
	 */
	virtual hit_test_handle on_mouse_button_up(const Eigen::Vector2f& in_position, mouse_button in_button) { return hit_test_handle::unhandled(); }

	/**
	 * @brief 处理鼠标点击事件
	 * @param in_position 本地坐标系中的鼠标位置
	 * @param in_button 点击的鼠标按钮
	 * @result 命中测试结果
	 */
	virtual void on_click(const Eigen::Vector2f& in_position, mouse_button in_button) { }

	/**
	 * @brief 处理鼠标双击事件
	 * @param in_position 本地坐标系中的鼠标位置
	 * @param in_button 双击的鼠标按钮
	 * @result 命中测试结果
	 */
	virtual void on_double_click(const Eigen::Vector2f& in_position, mouse_button in_button) { }

	/**
	 * @brief 处理鼠标滚轮事件
	 * @param in_position 本地坐标系中的鼠标位置
	 * @param in_delta 滚轮增量
	 * @result 命中测试结果
	 */
	virtual hit_test_handle on_mouse_wheel(const Eigen::Vector2f& in_position, const wheel_event& in_delta) { return hit_test_handle::unhandled(); }

protected:
	bool                                  enabled_ = true;
	invalidate_reason                     invalidate_{};
	visibility_t                          visibility_ = visibility_t::self_hit_test_invisible;
	std::optional<Eigen::Vector2f>        desired_size_{};
	std::weak_ptr<mwidget>                parent_;
	std::vector<std::shared_ptr<mwidget>> children_;
	geometry_t                            geometry_{};
};
