#include "uclass.h"
namespace refl {
	template<typename Func, typename... Args>
	inline auto FieldPtr::Call(Func func, Args&& ...args)const
	{
		using MemberFunc = decltype(fetch_method_t(func));
		MemberFunc fptr = (MemberFunc)data.method;
		return fptr(std::forward<Args>(args)...);
	}
	bool FieldPtr::Invoke(const sarray<ArgsView>& ArgsList)const{
		auto Call = type->vtable.Call;
		if (Call) {
			Call(this, ArgsList);
		}
		return Call;
	}
	bool FieldPtr::Invoke(std::vector<ArgsView>& ArgsList)const {
		auto Call = type->vtable.Call;
		if (Call) {
			auto params = GetParams();
			int paramsSize = params.size();
			int argsSize = ArgsList.size();
			if (argsSize < paramsSize && flag & FIELD_METHOD_VALUE_FLAG) {
				auto [argsPtr, valueSize] = value.method();
				if (argsSize + valueSize >= paramsSize) {
					for (int i = valueSize + argsSize - paramsSize; i < valueSize; i++) {
						ArgsList.push_back(*(argsPtr + i));
					}
					argsSize = paramsSize;
				}
			}
			if (argsSize < paramsSize) {
				return false;
			}

			for (int i = 0; i < paramsSize; i++) {
				if (ArgsList[i].cls != params[i] && !ArgsList[i].ConvertTo(params[i])) {
					return false;
				}
			}
			Call(this, ArgsList);
		}
		return Call;
	}
	std::vector<const UClass*> FieldPtr::GetParams() const {
		auto GetParams = type->vtable.GetParams;
		if (GetParams) {
			return GetParams(type);
		}
		return{};
	}
	template<typename T>
	class Field {
	public:
		inline static char data[fetch_args_size<T>()]{};
		inline static int index{0};
		template<typename V>
		static FieldPtr MakeField(V T::* ptr, Name name)
		{
			FieldPtr::Default value;
			Offset offset = reinterpret_cast<std::size_t>(&(reinterpret_cast<const T*>(0)->*ptr));
			FieldPtr::Data member = { offset };
			constexpr uint32_t flag = FIELD_MEMBER_FLAG | FIELD_ATTRIBUTE_FLAG;
			return { name, &TypeInfo<V>::StaticClass, member, value, flag };
		}
		template<typename R, typename ...Args>
		static FieldPtr MakeField(R(*ptr)(Args...), Name name, const sarray<ArgsValue>& args = {}) {
			uint32_t flag = FIELD_METHOD_FLAG;
			FieldPtr::Default value;
			if (args.size() > 0) {
				flag |= FIELD_METHOD_VALUE_FLAG;
				static const ArgsValueList argsValue(args, &data[index]);
				index += ArgsValueList::GetArgsSize(args);
				value.method = []() ->std::pair<ArgsView*, int> {
					return { argsValue.ptr , argsValue.num };
				};
			}
			FieldPtr::Data method = { *(Method*)&ptr };
			return { name, &TypeInfo<real_type_t<R>(*)(real_type_t<Args>...)>::StaticClass, method, value, flag };
		}
		template<typename R, typename ...Args>
		static FieldPtr MakeField(R(T::* ptr)(Args...), Name name, const sarray<ArgsValue>& args = {}) {
			uint32_t flag = FIELD_MEMBER_FLAG | FIELD_METHOD_FLAG;
			FieldPtr::Default value;
			if (args.size() > 0) {
				flag |= FIELD_METHOD_VALUE_FLAG;
				static const ArgsValueList argsValue(args, &data[index]);
				index += ArgsValueList::GetArgsSize(args);
				value.method = []() ->std::pair<ArgsView*, int> {
					return { argsValue.ptr , argsValue.num };
				};
			}
			FieldPtr::Data method = { *(Method*)&ptr };
			return { name, &TypeInfo<real_type_t<R>(*)(const void*,real_type_t<Args>...)>::StaticClass, method, value,flag };
		}
	};
}