#include "sys/glib/dark_theme.h"
#include "core/strings.h"

#include <array>
#include <cstring>
#include <memory>
#include <string_view>

#ifdef __GNUC__
/* Shut up */
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#include <gio/gio.h>
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif

namespace glib {

/* deleters */
template<typename T>
struct g_object_del {
	void operator()(T *p) const { ::g_object_unref(p); };
};

template<typename T>
struct g_variant_del {
	void operator()(T *p) const { ::g_variant_unref(p); };
};

template<typename T>
struct g_malloc_del {
	void operator()(T *p) const { (::g_free)(p); };
};

template<typename T>
using GObjectPtr = std::unique_ptr<T, g_object_del<T>>;

template<typename T>
using GVariantPtr = std::unique_ptr<T, g_variant_del<T>>;

template<typename T>
using GMallocPtr = std::unique_ptr<T, g_malloc_del<T>>;

bool IsInDarkTheme()
{
	GObjectPtr<GSettings> settings(::g_settings_new("org.gnome.desktop.interface"));
	if (!settings)
		return false;

	{
		/* first attempt to get the colorscheme */
		GVariantPtr<GVariant> val(::g_settings_get_value(settings.get(), "color-scheme"));
		if (!val)
			return false;

		/* this is free'd upon deconstruction of the GVariantPtr */
		gsize size;
		const gchar *str = ::g_variant_get_string(val.get(), &size);
		if (!str)
			return false;

		bool success = !std::strncmp(str, "prefer-dark", size);

		if (success)
			return true;
	}

	{

		GVariantPtr<GVariant> gtk_theme(::g_settings_get_value(settings.get(), "gtk-theme"));
		if (!gtk_theme)
			return false;

		gsize size;
		const gchar *str = ::g_variant_get_string(gtk_theme.get(), &size);
		if (!str)
			return false;

		if (Strings::IsGTKThemeDark({str, size}))
			return true;
	}

	/* welp, we tried */
	return false;
}

} // namespace glib
