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

#pragma once

#include "ISCW_FField.h"
#include "ISCW_UClass.h"
#include "ISCW_UObject.h"
#include "ISCW_UPropertyWrapper.h"
#include "ISCW_UStruct.h"
#include <memory>
#include <string>

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

namespace Sourcify
{
	// Mirror of EPropertyFlags in ObjectMacros.h
	enum class SCW_EPropertyFlags : uint64_t
	{
		CPF_None = 0,

		CPF_Edit = 0x0000000000000001,	///< Property is user-settable in the editor.
		CPF_ConstParm = 0x0000000000000002,	///< This is a constant function parameter
		CPF_BlueprintVisible = 0x0000000000000004,	///< This property can be read by blueprint code
		CPF_ExportObject = 0x0000000000000008,	///< Object can be exported with actor.
		CPF_BlueprintReadOnly = 0x0000000000000010,	///< This property cannot be modified by blueprint code
		CPF_Net = 0x0000000000000020,	///< Property is relevant to network replication.
		CPF_EditFixedSize = 0x0000000000000040,	///< Indicates that elements of an array can be modified, but its size cannot be changed.
		CPF_Parm = 0x0000000000000080,	///< Function/When call parameter.
		CPF_OutParm = 0x0000000000000100,	///< Value is copied out after function call.
		CPF_ZeroConstructor = 0x0000000000000200,	///< memset is fine for construction
		CPF_ReturnParm = 0x0000000000000400,	///< Return value.
		CPF_DisableEditOnTemplate = 0x0000000000000800,	///< Disable editing of this property on an archetype/sub-blueprint
		CPF_NonNullable = 0x0000000000001000,	///< Object property can never be null
		CPF_Transient = 0x0000000000002000,	///< Property is transient: shouldn't be saved or loaded, except for Blueprint CDOs.
		CPF_Config = 0x0000000000004000,	///< Property should be loaded/saved as permanent profile.
		CPF_RequiredParm = 0x0000000000008000,	///< Parameter must be linked explicitly in blueprint. Leaving the parameter out results in a compile error. 
		CPF_DisableEditOnInstance = 0x0000000000010000,	///< Disable editing on an instance of this class
		CPF_EditConst = 0x0000000000020000,	///< Property is uneditable in the editor.
		CPF_GlobalConfig = 0x0000000000040000,	///< Load config from base class, not subclass.
		CPF_InstancedReference = 0x0000000000080000,	///< Property is a component references.
		//CPF_								= 0x0000000000100000,	///<
		CPF_DuplicateTransient = 0x0000000000200000,	///< Property should always be reset to the default value during any type of duplication (copy/paste, binary duplication, etc.)
		//CPF_								= 0x0000000000400000,	///< 
		//CPF_    							= 0x0000000000800000,	///< 
		CPF_SaveGame = 0x0000000001000000,	///< Property should be serialized for save games, this is only checked for game-specific archives with ArIsSaveGame
		CPF_NoClear = 0x0000000002000000,	///< Hide clear button.
		//CPF_  							= 0x0000000004000000,	///<
		CPF_ReferenceParm = 0x0000000008000000,	///< Value is passed by reference; CPF_OutParam and CPF_Param should also be set.
		CPF_BlueprintAssignable = 0x0000000010000000,	///< MC Delegates only.  Property should be exposed for assigning in blueprint code
		CPF_Deprecated = 0x0000000020000000,	///< Property is deprecated.  Read it from an archive, but don't save it.
		CPF_IsPlainOldData = 0x0000000040000000,	///< If this is set, then the property can be memcopied instead of CopyCompleteValue / CopySingleValue
		CPF_RepSkip = 0x0000000080000000,	///< Not replicated. For non replicated properties in replicated structs 
		CPF_RepNotify = 0x0000000100000000,	///< Notify actors when a property is replicated
		CPF_Interp = 0x0000000200000000,	///< interpolatable property for use with cinematics
		CPF_NonTransactional = 0x0000000400000000,	///< Property isn't transacted
		CPF_EditorOnly = 0x0000000800000000,	///< Property should only be loaded in the editor
		CPF_NoDestructor = 0x0000001000000000,	///< No destructor
		//CPF_								= 0x0000002000000000,	///<
		CPF_AutoWeak = 0x0000004000000000,	///< Only used for weak pointers, means the export type is autoweak
		CPF_ContainsInstancedReference = 0x0000008000000000,	///< Property contains component references.
		CPF_AssetRegistrySearchable = 0x0000010000000000,	///< asset instances will add properties with this flag to the asset registry automatically
		CPF_SimpleDisplay = 0x0000020000000000,	///< The property is visible by default in the editor details view
		CPF_AdvancedDisplay = 0x0000040000000000,	///< The property is advanced and not visible by default in the editor details view
		CPF_Protected = 0x0000080000000000,	///< property is protected from the perspective of script
		CPF_BlueprintCallable = 0x0000100000000000,	///< MC Delegates only.  Property should be exposed for calling in blueprint code
		CPF_BlueprintAuthorityOnly = 0x0000200000000000,	///< MC Delegates only.  This delegate accepts (only in blueprint) only events with BlueprintAuthorityOnly.
		CPF_TextExportTransient = 0x0000400000000000,	///< Property shouldn't be exported to text format (e.g. copy/paste)
		CPF_NonPIEDuplicateTransient = 0x0000800000000000,	///< Property should only be copied in PIE
		CPF_ExposeOnSpawn = 0x0001000000000000,	///< Property is exposed on spawn
		CPF_PersistentInstance = 0x0002000000000000,	///< A object referenced by the property is duplicated like a component. (Each actor should have an own instance.)
		CPF_UObjectWrapper = 0x0004000000000000,	///< Property was parsed as a wrapper class like TSubclassOf<T>, FScriptInterface etc., rather than a USomething*
		CPF_HasGetValueTypeHash = 0x0008000000000000,	///< This property can generate a meaningful hash value.
		CPF_NativeAccessSpecifierPublic = 0x0010000000000000,	///< Public native access specifier
		CPF_NativeAccessSpecifierProtected = 0x0020000000000000,	///< Protected native access specifier
		CPF_NativeAccessSpecifierPrivate = 0x0040000000000000,	///< Private native access specifier
		CPF_SkipSerialization = 0x0080000000000000,	///< Property shouldn't be serialized, can still be exported to text
		CPF_TObjectPtr = 0x0100000000000000,	///< Property is a TObjectPtr<T> instead of a USomething*. Need to differentiate between TObjectclassOf and TObjectPtr
		CPF_ExperimentalOverridableLogic = 0x0200000000000000,	///< ****Experimental*** Property will use different logic to serialize knowing what changes are done against its default use the overridable information provided by the overridable manager on the object
		CPF_ExperimentalAlwaysOverriden = 0x0400000000000000,	///< ****Experimental*** Property should never inherit from the parent when using overridable serialization
	};

	inline SCW_EPropertyFlags operator|(const SCW_EPropertyFlags& Lhs, const SCW_EPropertyFlags& Rhs)
	{
		return static_cast<SCW_EPropertyFlags>(static_cast<uint64_t>(Lhs) | static_cast<uint64_t>(Rhs));
	}

	inline SCW_EPropertyFlags operator&(const SCW_EPropertyFlags& Lhs, const SCW_EPropertyFlags& Rhs)
	{
		return static_cast<SCW_EPropertyFlags>(static_cast<uint64_t>(Lhs) & static_cast<uint64_t>(Rhs));
	}

	inline bool operator!(const SCW_EPropertyFlags& Flags)
	{
		return static_cast<uint64_t>(Flags) == 0;
	}

	// Mirror of EPropertyExportCPPFlags in UnrealType.h
	enum class SCW_EPropertyExportCPPFlags : uint32_t
	{
		/** Indicates that there are no special C++ export flags */
		CPPF_None = 0x00000000,
		/** Indicates that we are exporting this property's CPP text for an optional parameter value */
		CPPF_OptionalValue = 0x00000001,
		/** Indicates that we are exporting this property's CPP text for an argument or return value */
		CPPF_ArgumentOrReturnValue = 0x00000002,
		/** Indicates thet we are exporting this property's CPP text for C++ definition of a function. */
		CPPF_Implementation = 0x00000004,
		/** Indicates that we are exporting this property's CPP text with an custom type name */
		CPPF_CustomTypeName = 0x00000008,
		/** No 'const' keyword */
		CPPF_NoConst = 0x00000010,
		/** No reference '&' sign */
		CPPF_NoRef = 0x00000020,
		/** No static array [%d] */
		CPPF_NoStaticArray = 0x00000040,
		/** Blueprint compiler generated C++ code */
		CPPF_BlueprintCppBackend = 0x00000080,
		/** Indicates to not use TObjectPtr but use USomething* instead */
		CPPF_NoTObjectPtr = 0x00000100,
	};

	inline SCW_EPropertyExportCPPFlags operator|(const SCW_EPropertyExportCPPFlags& Lhs, const SCW_EPropertyExportCPPFlags& Rhs)
	{
		return static_cast<SCW_EPropertyExportCPPFlags>(static_cast<uint32_t>(Lhs) | static_cast<uint32_t>(Rhs));
	}

	inline SCW_EPropertyExportCPPFlags operator&(const SCW_EPropertyExportCPPFlags& Lhs, const SCW_EPropertyExportCPPFlags& Rhs)
	{
		return static_cast<SCW_EPropertyExportCPPFlags>(static_cast<uint32_t>(Lhs) & static_cast<uint32_t>(Rhs));
	}

	// Mirror of ELifetimeCondition in CoreNetTypes.h
	enum class SCW_ELifetimeCondition : uint32_t
	{
		COND_None = 0,							// This property has no condition, and will send anytime it changes
		COND_InitialOnly = 1,					// This property will only attempt to send on the initial bunch
		COND_OwnerOnly = 2,						// This property will only send to the actor's owner
		COND_SkipOwner = 3,						// This property send to every connection EXCEPT the owner
		COND_SimulatedOnly = 4,					// This property will only send to simulated actors
		COND_AutonomousOnly = 5,				// This property will only send to autonomous actors
		COND_SimulatedOrPhysics = 6,			// This property will send to simulated OR bRepPhysics actors
		COND_InitialOrOwner = 7,				// This property will send on the initial packet, or to the actors owner
		COND_Custom = 8,						// This property has no particular condition, but wants the ability to toggle on/off via SetCustomIsActiveOverride
		COND_ReplayOrOwner = 9,					// This property will only send to the replay connection, or to the actors owner
		COND_ReplayOnly = 10,					// This property will only send to the replay connection
		COND_SimulatedOnlyNoReplay = 11,		// This property will send to actors only, but not to replay connections
		COND_SimulatedOrPhysicsNoReplay = 12,	// This property will send to simulated Or bRepPhysics actors, but not to replay connections
		COND_SkipReplay = 13,					// This property will not send to the replay connection
		COND_Dynamic = 14,						// This property wants to override the condition at runtime. Defaults to always replicate until you override it to a new condition.
		COND_Never = 15,						// This property will never be replicated
		COND_NetGroup = 16,						// This subobject will replicate to connections that are part of the same group the subobject is registered to. Not usable on properties.
		COND_Max = 17
	};

	// Mirror of EPropertyPortFlags in PropertyPortFlags.h
	enum class SCW_EPropertyPortFlags : uint32_t
	{
		/** No special property exporting flags */
		PPF_None = 0x00000000,

		/** Indicates that property data should be wrapped in quotes (for some types of properties) */
		PPF_Delimited = 0x00000001,

		/** Indicates that the object reference should be verified */
		PPF_CheckReferences = 0x00000002,

		PPF_ExportsNotFullyQualified = 0x00000004,

		PPF_AttemptNonQualifiedSearch = 0x00000008,

		/** Indicates that importing values for config properties is disallowed */
		PPF_RestrictImportTypes = 0x00000010,

		/** Indicates that this is a blueprint pin or something else that is saved to disk as import text */
		PPF_SerializedAsImportText = 0x00000020,

		/**
		 * Set if this is being exported/imported for an external editor format like CSV.
		 * If true, it uses authored names instead of internal names and default values are always written out.
		 */
		PPF_ExternalEditor = 0x00000040,

		/** only include properties which are marked CPF_InstancedReference */
		PPF_SubobjectsOnly = 0x00000080,

		/**
		 * Indicates that two object should be considered identical
		 * if the property values for both objects are all identical
		 */
		PPF_DeepComparison = 0x00000100,

		/**
		 * Similar to PPF_DeepComparison, except that template components are always compared using standard object
		 * property comparison logic (basically if the pointers are different, then the property isn't identical)
		 */
		PPF_DeepCompareInstances = 0x00000200,

		/**
		 * Only do a deep comparison if the objects are native created default subobjects.
		 * This can be used to use the legacy FPropertyObjectBase::Identical behavior where subobjects that were
		 * not created as a default subobject would always return false for a deep compare.
		 * Requires PPF_DeepComparison or PPF_DeepCompareInstances to also be set
		 */
		PPF_DeepCompareDSOsOnly = 0x00000400,

		/**
		 * Set if this operation is copying in memory (for copy/paste) instead of exporting to a file. There are
		 * some subtle differences between the two
		 */
		PPF_Copy = 0x00000800,

		/** Set when duplicating objects via serialization */
		PPF_Duplicate = 0x00001000,

		/** Indicates that object property values should be exported without the package or class information */
		PPF_SimpleObjectText = 0x00002000,

		/** Set if this export is going to be used for diffing and may want to omit certain data that doesn't make sense for comparison */
		PPF_ForDiff = 0x00004000,

		/**
		 * Set if this export is going to be used for diffing and may want to omit certain data related to CDOs/archetypes that doesn't make sense when comparing an instance of an object/property/value.
		 * Requires PPF_ForDiff to also be set.
		 */
		PPF_ForDiffInstanceOnly = 0x00008000,

		/** parsing default properties - allow text for transient properties to be imported - also modifies ObjectProperty importing slightly for subobjects */
		PPF_ParsingDefaultProperties = 0x00010000,

		/** indicates that non-categorized transient properties should be exported (by default, they would not be) */
		PPF_IncludeTransient = 0x00020000,

		/** Indicates that any instanced subobject properties should get a duplicate of the specified object rather than having its value set to the specified text */
		PPF_InstanceSubobjects = 0x00040000,

		/** indicates that we're exporting properties for display in the property window. - used to hide EditHide items in collapsed structs */
		PPF_PropertyWindow = 0x00080000,

		//								= 0x00100000,

		/** Force fully qualified object names (for debug dumping) */
		PPF_DebugDump = 0x00200000,

		/** Set when duplicating objects for PIE */
		PPF_DuplicateForPIE = 0x00400000,

		/** Set when exporting just an object declaration, to be followed by another call with PPF_SeparateDefine */
		PPF_SeparateDeclare = 0x00800000,

		/** Set when exporting just an object definition, preceded by another call with PPF_SeparateDeclare */
		PPF_SeparateDefine = 0x01000000,

		/** Used by 'watch value' while blueprint debugging*/
		PPF_BlueprintDebugView = 0x02000000,

		/** Exporting properties for console variables. */
		PPF_ConsoleVariable = 0x04000000,

		/** Ignores CPF_Deprecated flag */
		PPF_UseDeprecatedProperties = 0x08000000,

		//								= 0x10000000,

		/** Ignores CPF_SkipSerialization flag when using tagged serialization */
		PPF_ForceTaggedSerialization = 0x20000000,

		/** Set when duplicating objects verbatim (doesn't reset unique IDs) */
		PPF_DuplicateVerbatim = 0x40000000,

		//								= 0x80000000,
	};


	class ISCW_FProperty : public virtual ISCW_FField
	{
	public:
		virtual ~ISCW_FProperty() = default;

		virtual void ExportTextItem_InContainer(wstring& ValueStr, ISCW_UObjectConstPtr ContainerPtr, SCW_EPropertyPortFlags PortFlags = SCW_EPropertyPortFlags::PPF_None) const = 0;
		
		virtual wstring GetAuthoredName() const = 0;

		virtual SCW_ELifetimeCondition GetBlueprintReplicationCondition() const = 0;

		virtual wstring GetCPPType(wstring* ExtendedTypeText = nullptr, SCW_EPropertyExportCPPFlags CPPExportFlags = SCW_EPropertyExportCPPFlags::CPPF_None) const = 0;

		virtual wstring GetName() const = 0;

		virtual wstring GetNameCPP() const = 0;

		virtual ISCW_UClassConstPtr GetOwnerClass() const = 0;

		virtual ISCW_UClassPtr GetOwnerClass() = 0;

		virtual ISCW_UObjectConstPtr GetOwnerUObject() const = 0;

		virtual ISCW_UObjectPtr GetOwnerUObject() = 0;

		virtual ISCW_UStructConstPtr GetOwnerStruct() const = 0;
		
		virtual ISCW_UStructPtr GetOwnerStruct() = 0;

		virtual ISCW_UPropertyWrapperPtr GetUPropertyWrapper() = 0;
			
		virtual SCW_EPropertyFlags GetPropertyFlags() const = 0;

		virtual wstring GetRepNotifyFuncName() const = 0;

		virtual bool HasAllPropertyFlags(SCW_EPropertyFlags FlagsToCheck) const = 0;

		virtual bool HasAnyPropertyFlags(SCW_EPropertyFlags FlagsToCheck) const = 0;

		virtual bool Identical_InContainer(shared_ptr<const ISCW_UObject> A, shared_ptr<const ISCW_UObject> B, SCW_EPropertyPortFlags PortFlags = SCW_EPropertyPortFlags::PPF_None) const = 0;

		// Not supporting FOutputdevice for now since none of our calls use it
		virtual const wchar_t* ImportText_InContainer(const wchar_t* Buffer, ISCW_UObjectPtr Container, ISCW_UObjectPtr OwnerObject, SCW_EPropertyPortFlags PortFlags/*, FOutputDevice* ErrorText = (FOutputDevice*)GWarn*/) const = 0;
	
		virtual void SetPropertyFlags(SCW_EPropertyFlags InFlags) = 0;

		virtual shared_ptr<ISCW_FProperty> ToFPropertyPtr() = 0;
		virtual shared_ptr<const ISCW_FProperty> ToFPropertyPtr() const = 0;
	};

	using ISCW_FPropertyPtr = shared_ptr<ISCW_FProperty>;
	using ISCW_FPropertyConstPtr = shared_ptr<const ISCW_FProperty>;
} // namespace Sourcify
