#include "mwidget.h"

#include "window/mwindow.h"
#include "geometry/dpi_helper.h"

mwidget::~mwidget() {
	remove_from_parent();
}

const mwindow* mwidget::get_window() const {
	if (const auto parent = get_parent()) {
		return parent->get_window();
	}
	return nullptr;
}

mwindow* mwidget::get_window() {
	if (const auto parent = get_parent()) {
		return parent->get_window();
	}
	return nullptr;
}

void mwidget::set_geometry(const geometry_t& in_geometry) {
	geometry_ = in_geometry;
}

void mwidget::cache_desired_size(float in_layout_scale_multiplier, bool in_force) {
	if (!in_force && desired_size_.has_value())
		return;
	desired_size_ = compute_desired_size(in_layout_scale_multiplier);
}

auto mwidget::get_dpi_scale() const -> float {
	if (const auto window = get_window())
		return window->get_dpi_scale();
	return 1.f;
}

void mwidget::set_parent(const std::shared_ptr<mwidget>& in_parent) {
	// 先从原父节点中移除
	remove_from_parent();

	// 设置新的父节点
	parent_ = in_parent;
	in_parent->add_child(shared_from_this());
}

void mwidget::remove_from_parent() {
	const auto parent = get_parent();
	if (!parent)
		return;

	parent->remove_child(shared_from_this());
}

void mwidget::add_child(const std::shared_ptr<mwidget>& in_child) {
#if DEBUG
	// 避免重复添加
	const auto& it = std::ranges::find_if(children_, [&](const auto& child) { return child == in_child; });
	assert(it == children_.end());
#endif
	children_.push_back(in_child);
	invalidate(invalidate_reason::layout);
}

void mwidget::remove_child(const std::shared_ptr<mwidget>& in_child) {
	const auto& it = std::ranges::find_if(children_, [&](const auto& child) {
		return child == in_child;
	});
	if (it != children_.end()) {
		children_.erase(it);
	}
	invalidate(invalidate_reason::layout);
}

void mwidget::invalidate(invalidate_reason in_reason) {
	// 设置失效标记
	set_flag(invalidate_, in_reason);

	// 通知父组件
	if (const auto parent = get_parent()) {
		parent->invalidate(in_reason);
	}

	// 如果是布局失效, 重置期望大小
	if (has_any_flag(in_reason, invalidate_reason::layout)) {
		desired_size_.reset();
	}
}

bool mwidget::can_hit_test() const {
	// 不可见组件不参与命中测试
	if (has_any_flag(visibility_, visibility_t::any_invisible)) {
		return false;
	}

	// 如果整个组件树都不可点击
	if (has_flag(visibility_, visibility_t::hit_test_invisible)) {
		return false;
	}

	// 如果组件自身不可点击（但子组件可以）
	if (has_flag(visibility_, visibility_t::self_hit_test_invisible)) {
		return false;
	}

	return true;
}
