#pragma once
#include "field.h"
#include "view.h"
#include "meta.h"
#include "convert.h"
namespace refl {
	enum ClassFlag :uint32_t {
		CLASS_NONE_FLAG      = 0,
		CLASS_TRIVIAL_FLAG   = 1 << 0,
		CLASS_POINTER_FLAG   = 1 << 1,
		CLASS_ARRAY_FLAG     = 1 << 2,
		CLASS_CONTAINER_FLAG = 1 << 3,
		CLASS_SEQUENCE_FLAG  = 1 << 4,
		CLASS_MAP_FLAG		 = 1 << 5,
		CLASS_PARENT_FLAG    = 1 << 6,
	};
	using enum ClassFlag;
	enum EFieldFind :uint32_t {
		FIND_ALL_FIELD = 0,
		FIND_ALL_MEMBER,
		FIND_ALL_METHOD,
		FIND_FIELD,
		FIND_CTOR,
		FIND_MEMBER,
		FIND_METHOD,
		FIND_METHODS,//函数重载 特别是构造函数
	};
	struct vtable_uclass
	{
		//class
		const sarray<const FieldPtr> (*GetFields)(const UClass*, EFieldFind find, const Name& name);
		//function
		sarray<const UClass*>(*GetParams)(const UClass*);
		//function
		void (*Call)(const FieldPtr*, const sarray<Any>& ArgsList);
		//meta
		const UClass* (*GetMeta)(const Name&);
		//object
		bool (*Construct)(void* ptr,const UClass* cls, const sarray<Any>& ArgsList);
		void (*Destruct)(void*);
	};
	class UClass{
	public:
		Name name;
		uint32_t size;
		uint32_t flag{0};
		const UClass* parent;
		vtable_uclass vtable{};
	inline static std::unordered_map<Name, const UClass*> MetaTable;
	public:
		constexpr UClass(std::string_view name, uint32_t size, const UClass* parent = nullptr)
			:name(name), size(size), parent(parent){}
		AnyView New(void* ptr = nullptr, const sarray<Any>& ArgsList = {}) const {
			if (ptr == nullptr) {
				ptr = malloc(size);
				Construct(ptr, ArgsList);
			}
			return { ptr , this };
		}
		template<typename T>
		T* New(T* ptr = nullptr, const sarray<Any>& ArgsList = {}) const{
			if (!IsChildOf<T>(true)) {
				return nullptr;
			}
			if (ptr == nullptr) {
				ptr = (T*)malloc(size);
			}
			
			Construct(ptr, ArgsList);
			return ptr;
		}
		bool IsChildOf(const UClass* cls, bool bthis = false) const {
			const UClass* _parent = bthis ? this : parent;
			while (_parent != nullptr) {
				if (_parent == cls) {
					return true;
				}
				_parent = _parent->parent;
			}
			return false;
		}
		template<typename T>
		bool IsChildOf(bool bthis = false) const {
			return IsChildOf(&TypeInfo<T>::StaticClass, bthis);
		}
	public:
		const sarray<const FieldPtr> GetFields(EFieldFind find, const Name& name)const {
			if (vtable.GetFields) {
				return vtable.GetFields(this, find, name);
			}
			return {};
		}
		bool Construct(void* ptr, const sarray<Any>& ArgsList = {})const;
		void Destruct(void* ptr)const {
			if (vtable.Destruct) {
				vtable.Destruct(ptr);
			}
		}
	public:
		template<typename T>
		static bool Construct(void* ptr, const UClass* cls, const sarray<Any>& ArgsList = {}) {
			int argsSize = ArgsList.size();
			if (argsSize == 0) {
				if constexpr (std::is_trivially_constructible_v<T>) {
					std::construct_at((T*)ptr);
					return true;
				}
				return false;
			}
			if (argsSize == 1 && ArgsList[0]->Check(cls)) {
				*(T*)ptr = *(const T*)ArgsList[0]->ptr;
				return true;
			}
			return false;
		}
	};
}