#pragma once
#include "game/game.hpp"
#include "script_value.hpp"

namespace ui_scripting
{
	class lightuserdata
	{
	public:
		lightuserdata(void*);

		bool operator==(const lightuserdata& other);
		bool operator!=(const lightuserdata& other);

		void* ptr;
	};

	class userdata
	{
	public:
		userdata(void*);

		userdata(const userdata& other);
		userdata(userdata&& other) noexcept;

		~userdata();

		userdata& operator=(const userdata& other);
		userdata& operator=(userdata&& other) noexcept;

		bool operator==(const userdata& other);
		bool operator!=(const userdata& other);

		script_value get(const script_value& key) const;
		void set(const script_value& key, const script_value& value) const;

		void* ptr;

	private:
		void add();
		void release();

		int ref{};
	};

	class table
	{
	public:
		table();
		table(game::hks::HashTable* ptr_);

		table(const table& other);
		table(table&& other) noexcept;

		~table();

		table& operator=(const table& other);
		table& operator=(table&& other) noexcept;

		bool operator==(const table& other);
		bool operator!=(const table& other);

		script_value get(const script_value& key) const;
		void set(const script_value& key, const script_value& value) const;

		game::hks::HashTable* ptr;

	private:
		void add();
		void release();

		int ref{};
	};

	class function
	{
	public:
		function(game::hks::cclosure*, game::hks::HksObjectType);

		function(const function& other);
		function(function&& other) noexcept;

		~function();

		function& operator=(const function& other);
		function& operator=(function&& other) noexcept;

		bool operator==(const function& other);
		bool operator!=(const function& other);

		arguments call(const arguments& arguments) const;

		game::hks::cclosure* ptr;
		game::hks::HksObjectType type;

	private:
		void add();
		void release();

		int ref{};
	};

	class stack final
	{
	public:
		stack();

		void save(int num_args);
		void fix();

		stack(stack&&) = delete;
		stack(const stack&) = delete;
		stack& operator=(stack&&) = delete;
		stack& operator=(const stack&) = delete;

	private:
		game::hks::lua_State* state;

		int num_args_;
		int num_calls_;

		uint64_t base_bottom_;
		uint64_t top_bottom_;
		uint64_t callstack_;
	};
}
