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

#include "SCW_FInstancedPropertyBag.h"
#if ISCW_UE_VERSION_NEWER_THAN_OR_EQUAL(5,5,0)
#include "SourcifyCoreUEWrapperModule.h"
#include "StructUtils/PropertyBag.h"

using namespace Sourcify;

SCW_FInstancedPropertyBag::SCW_FInstancedPropertyBag(FInstancedPropertyBag& InBag)
	: Bag(InBag)
{
}

vector<ISCW_UObjectPtr> SCW_FInstancedPropertyBag::GetDescriptorTypeObjects() const
{
	vector<ISCW_UObjectPtr> Result;
	const UPropertyBag* BagStruct = Bag.GetPropertyBagStruct();
	if (!BagStruct)
	{
		return Result;
	}

	for (const FPropertyBagPropertyDesc& Desc : BagStruct->GetPropertyDescs())
	{
		if (Desc.ValueTypeObject)
		{
			UObject* MutableObj = const_cast<UObject*>(Desc.ValueTypeObject.Get());
			Result.push_back(FSourcifyCoreUEWrapper::Get().Wrap(*MutableObj));
		}
	}
	return Result;
}

void SCW_FInstancedPropertyBag::ReplaceDescriptorType(ISCW_UObjectConstPtr oldType, ISCW_UObjectPtr newType)
{
	const UPropertyBag* BagStruct = Bag.GetPropertyBagStruct();
	if (!BagStruct)
	{
		return;
	}

	const UObject* RawOldType = FSourcifyCoreUEWrapper::Unwrap(oldType);
	UObject* RawNewType = const_cast<UObject*>(FSourcifyCoreUEWrapper::Unwrap(newType));

	TArray<FPropertyBagPropertyDesc> NewDescs;
	bool bFoundMatch = false;
	for (const FPropertyBagPropertyDesc& Desc : BagStruct->GetPropertyDescs())
	{
		FPropertyBagPropertyDesc NewDesc = Desc;
		if (Desc.ValueTypeObject == RawOldType)
		{
			NewDesc.ValueTypeObject = RawNewType;
			bFoundMatch = true;
		}
		NewDescs.Add(NewDesc);
	}

	if (bFoundMatch)
	{
		const UPropertyBag* NewBagStruct = UPropertyBag::GetOrCreateFromDescs(NewDescs);
		Bag.MigrateToNewBagStruct(NewBagStruct);
	}
}

vector<wstring> SCW_FInstancedPropertyBag::GetPropertyNamesWithType(ISCW_UObjectConstPtr typeObject) const
{
	vector<wstring> Result;
	const UPropertyBag* BagStruct = Bag.GetPropertyBagStruct();
	if (!BagStruct)
	{
		return Result;
	}

	const UObject* RawType = FSourcifyCoreUEWrapper::Unwrap(typeObject);
	for (const FPropertyBagPropertyDesc& Desc : BagStruct->GetPropertyDescs())
	{
		if (Desc.ValueTypeObject == RawType)
		{
			Result.push_back(*Desc.Name.ToString());
		}
	}
	return Result;
}

wstring SCW_FInstancedPropertyBag::GetPropertyValueAsString(const wstring& propertyName) const
{
	const FName PropName(propertyName.c_str());
	const FPropertyBagPropertyDesc* Desc = Bag.FindPropertyDescByName(PropName);
	if (!Desc || !Desc->CachedProperty)
	{
		return L"";
	}

	FString ValueStr;
	const uint8* ValuePtr = Bag.GetValue().GetMemory() + Desc->CachedProperty->GetOffset_ForInternal();
	Desc->CachedProperty->ExportTextItem_Direct(ValueStr, ValuePtr, nullptr, nullptr, PPF_None);
	return *ValueStr;
}

void SCW_FInstancedPropertyBag::SetPropertyValueFromString(const wstring& propertyName, const wstring& value)
{
	const FName PropName(propertyName.c_str());
	const FPropertyBagPropertyDesc* Desc = Bag.FindPropertyDescByName(PropName);
	if (!Desc || !Desc->CachedProperty)
	{
		return;
	}

	uint8* ValuePtr = Bag.GetMutableValue().GetMemory() + Desc->CachedProperty->GetOffset_ForInternal();
	Desc->CachedProperty->ImportText_Direct(value.c_str(), ValuePtr, nullptr, PPF_None);
}
#endif // ISCW_UE_VERSION_NEWER_THAN_OR_EQUAL(5,5,0)