/**
 * Copyright 2022-2025 Theai, Inc. dba Inworld AI
 */
#include "Graph/InworldProcessContext.h"

THIRD_PARTY_INCLUDES_START
#include "InworldRuntimeLibrary/inworld.h"
THIRD_PARTY_INCLUDES_END

namespace
{
static thread_local inworld::ProcessContext* g_process_context = nullptr;
}

UInworldProcessContext* UInworldProcessContext::Create(UObject* Owner, const TMap<FName, FInworldDataHandle>& GraphRuntimeData)
{
	UInworldProcessContext* ProcessContext = NewObject<UInworldProcessContext>(Owner);
	ProcessContext->RuntimeDataMap = GraphRuntimeData;
	return ProcessContext;
}

void UInworldProcessContext::SetProcessContext(inworld::ProcessContext* in_process_context)
{
	g_process_context = in_process_context;
}

inworld::ProcessContext* UInworldProcessContext::GetProcessContext()
{
	return g_process_context;
}

inworld::StatusOr_TextEmbedderInterface UInworldProcessContext::GetTextEmbedder(const FString& Id) const
{
	if (g_process_context == nullptr)
	{
		return inworld::Status();
	}
	return g_process_context->GetComponent_TextEmbedderInterface(TCHAR_TO_UTF8(*Id));
}

bool UInworldProcessContext::GetRuntimeData(FName Key, FInworldDataHandle& OutData) const
{
	if (const FInworldDataHandle* FoundData = RuntimeDataMap.Find(Key); FoundData != nullptr)
	{
		OutData = *FoundData;
		return true;
	}
	return false;
}

bool UInworldProcessContext::GetRuntimeBool(FName Key, bool& OutBool) const
{
	if (RuntimeDataMap.Contains(Key))
	{
		if (FInworldData_Struct* Struct = RuntimeDataMap[Key].Unwrap<FInworldData_Struct>(); Struct != nullptr)
		{
			if (FInworldData_Bool Bool; Struct->GetData(Bool))
			{
				OutBool = Bool.Bool;
				return true;
			}
		}
	}
	return false;
}

bool UInworldProcessContext::GetRuntimeInt(FName Key, int32& OutInt) const
{
	if (RuntimeDataMap.Contains(Key))
	{
		if (FInworldData_Struct* Struct = RuntimeDataMap[Key].Unwrap<FInworldData_Struct>(); Struct != nullptr)
		{
			if (FInworldData_Int Int; Struct->GetData(Int))
			{
				OutInt = Int.Int;
				return true;
			}
		}
	}
	return false;
}

bool UInworldProcessContext::GetRuntimeFloat(FName Key, float& OutFloat) const
{
	if (RuntimeDataMap.Contains(Key))
	{
		if (FInworldData_Struct* Struct = RuntimeDataMap[Key].Unwrap<FInworldData_Struct>(); Struct != nullptr)
		{
			if (FInworldData_Float Float; Struct->GetData(Float))
			{
				OutFloat = Float.Float;
				return true;
			}
		}
	}
	return false;
}

bool UInworldProcessContext::GetRuntimeObject(FName Key, TSubclassOf<UObject> ObjectClass, UObject*& OutObject) const
{
	if (RuntimeDataMap.Contains(Key))
	{
		if (FInworldData_Struct* Struct = RuntimeDataMap[Key].Unwrap<FInworldData_Struct>(); Struct != nullptr)
		{
			if (FInworldData_Object Object; Struct->GetData(Object) && Object.Object != nullptr)
			{
				OutObject = Object.Object;
				return OutObject != nullptr && OutObject->GetClass() == ObjectClass;
			}
		}
	}
	return false;
}
