// Copyright (c) 2024 Codemongous LLC. All Rights Reserved.

#pragma once

#include "ISCW_UStruct.h"
#include <memory>
#include <string>
#include <vector>

using std::shared_ptr;
using std::vector;
using std::wstring;

namespace Sourcify
{
	class ISCW_FImplementedInterface;
	class ISCW_FProperty;
	class ISCW_UObject;
	class ISCW_UField;
	class ISCW_UFunction;
	class ISCW_UScriptStruct;

	// Mirror of EClassFlags in ObjectMacros.h
	enum class SCW_EClassFlags : uint32_t
	{
		/** No Flags */
		CLASS_None = 0x00000000u,
		/** Class is abstract and can't be instantiated directly. */
		CLASS_Abstract = 0x00000001u,
		/** Save object configuration only to Default INIs, never to local INIs. Must be combined with CLASS_Config */
		CLASS_DefaultConfig = 0x00000002u,
		/** Load object configuration at construction time. */
		CLASS_Config = 0x00000004u,
		/** This object type can't be saved; null it out at save time. */
		CLASS_Transient = 0x00000008u,
		/** This object type may not be available in certain context. (i.e. game runtime or in certain configuration). Optional class data is saved separately to other object types. (i.e. might use sidecar files) */
		CLASS_Optional = 0x00000010u,
		/** */
		CLASS_MatchedSerializers = 0x00000020u,
		/** Indicates that the config settings for this class will be saved to Project/User*.ini (similar to CLASS_GlobalUserConfig) */
		CLASS_ProjectUserConfig = 0x00000040u,
		/** Class is a native class - native interfaces will have CLASS_Native set, but not RF_MarkAsNative */
		CLASS_Native = 0x00000080u,
		/** Don't export to C++ header. */
		//CLASS_NoExport UE_DEPRECATED(5.1, "CLASS_NoExport should no longer be used. It is no longer being set by engine code.") = 0x00000100u,
		/** Do not allow users to create in the editor. */
		CLASS_NotPlaceable = 0x00000200u,
		/** Handle object configuration on a per-object basis, rather than per-class. */
		CLASS_PerObjectConfig = 0x00000400u,

		/** Whether SetUpRuntimeReplicationData still needs to be called for this class */
		CLASS_ReplicationDataIsSetUp = 0x00000800u,

		/** Class can be constructed from editinline New button. */
		CLASS_EditInlineNew = 0x00001000u,
		/** Display properties in the editor without using categories. */
		CLASS_CollapseCategories = 0x00002000u,
		/** Class is an interface **/
		CLASS_Interface = 0x00004000u,
		/**  Config for this class is overridden in platform inis, reload when previewing platforms **/
		CLASS_PerPlatformConfig = 0x00008000u,
		/** all properties and functions in this class are const and should be exported as const */
		CLASS_Const = 0x00010000u,

		/** Class flag indicating objects of this class need deferred dependency loading */
		CLASS_NeedsDeferredDependencyLoading = 0x00020000u,

		/** Indicates that the class was created from blueprint source material */
		CLASS_CompiledFromBlueprint = 0x00040000u,

		/** Indicates that only the bare minimum bits of this class should be DLL exported/imported */
		CLASS_MinimalAPI = 0x00080000u,

		/** Indicates this class must be DLL exported/imported (along with all of it's members) */
		CLASS_RequiredAPI = 0x00100000u,

		/** Indicates that references to this class default to instanced. Used to be subclasses of UComponent, but now can be any UObject */
		CLASS_DefaultToInstanced = 0x00200000u,

		/** Indicates that the parent token stream has been merged with ours. */
		CLASS_TokenStreamAssembled = 0x00400000u,
		/** Class has component properties. */
		CLASS_HasInstancedReference = 0x00800000u,
		/** Don't show this class in the editor class browser or edit inline new menus. */
		CLASS_Hidden = 0x01000000u,
		/** Don't save objects of this class when serializing */
		CLASS_Deprecated = 0x02000000u,
		/** Class not shown in editor drop down for class selection */
		CLASS_HideDropDown = 0x04000000u,
		/** Class settings are saved to <AppData>/..../Blah.ini (as opposed to CLASS_DefaultConfig) */
		CLASS_GlobalUserConfig = 0x08000000u,
		/** Class was declared directly in C++ and has no boilerplate generated by UnrealHeaderTool */
		CLASS_Intrinsic = 0x10000000u,
		/** Class has already been constructed (maybe in a previous DLL version before hot-reload). */
		CLASS_Constructed = 0x20000000u,
		/** Indicates that object configuration will not check against ini base/defaults when serialized */
		CLASS_ConfigDoNotCheckDefaults = 0x40000000u,
		/** Class has been consigned to oblivion as part of a blueprint recompile, and a newer version currently exists. */
		CLASS_NewerVersionExists = 0x80000000u,
	};

	enum class SCW_EIncludeSuperFlagType : uint8_t
	{
		ExcludeSuper,
		IncludeSuper
	};

	enum class SCW_EObjectInitializerOptions : uint8_t
	{
		None = 0,
		CopyTransientsFromClassDefaults = 1 << 0, // copy transient from the class defaults instead of the pass in archetype ptr
		InitializeProperties = 1 << 1, // initialize property values with the archetype values
	};

	class ISCW_UClass : public virtual ISCW_UStruct
	{
	public:
		virtual ~ISCW_UClass() = default;

		virtual shared_ptr<ISCW_UClass> ToUClassPtr() = 0;
		virtual shared_ptr<const ISCW_UClass> ToUClassPtr() const = 0;

		virtual void ClassConstructor(shared_ptr<ISCW_UObject> ObjectToConstruct, shared_ptr<ISCW_UObject> ArchitypeObject, SCW_EObjectInitializerOptions ObjectInitializerOptions) const = 0;

		virtual shared_ptr<ISCW_UFunction> FindFunctionByName(const wstring& InName, SCW_EIncludeSuperFlagType IncludeSuper = SCW_EIncludeSuperFlagType::IncludeSuper) const = 0;

		virtual shared_ptr<ISCW_UObject> FindArchetype(shared_ptr<const ISCW_UClass> ArchetypeClass, const wstring& ArchetypeName) const = 0;

		virtual void GenerateFunctionList(vector<wstring>& OutArray) const = 0;

		virtual shared_ptr<ISCW_UClass> GetAuthoritativeClass() const = 0;

		virtual shared_ptr<ISCW_UObject> GetClassDefaultObject() const = 0;

		virtual shared_ptr<ISCW_UObject> GetClassGeneratedBy() const = 0;

		virtual wstring GetClassPathName() const = 0;

		virtual wstring GetConfigName() const = 0;

		virtual shared_ptr<ISCW_UObject> GetDefaultObject(bool bCreateIfNeeded = true) const = 0;

		virtual void GetDefaultObjectSubobjects(vector<shared_ptr<ISCW_UObject>>& OutDefaultSubobjects) const = 0;

		virtual shared_ptr<ISCW_UScriptStruct> GetSparseClassDataStruct() const = 0;
		
		virtual shared_ptr<ISCW_UClass> GetSuperClass() const = 0;

		virtual bool HasAllClassFlags(SCW_EClassFlags FlagsToCheck) const = 0;
		
		virtual bool HasAnyClassFlags(SCW_EClassFlags FlagsToCheck) const = 0;

		virtual vector<shared_ptr<ISCW_FImplementedInterface>> Interfaces() const = 0;

		virtual bool IsChildOf(shared_ptr<const ISCW_UClass> SomeBase) const = 0;

		virtual bool IsChildOf_AActor() const = 0;

		virtual bool IsChildOf_UActorComponent() const = 0;

		virtual bool IsChildOf_UInterface() const = 0;
		
		virtual bool IsInterface() const = 0;
	};

	using ISCW_UClassConstPtr = shared_ptr<const ISCW_UClass>;
	using ISCW_UClassPtr = shared_ptr<ISCW_UClass>;
} // namespace Sourcify