/**
 * Copyright 2022-2025 Theai, Inc. dba Inworld AI
 */

#include "Core/InworldInputStreamTransformer.h"

#include "Graph/InworldData.h"
#include "Graph/InworldGraph.h"

THIRD_PARTY_INCLUDES_START
#include "InworldRuntimeLibrary/inworld.h"
THIRD_PARTY_INCLUDES_END

void FInworldInputStreamTransformer::transformCallback(void* opaque_this, int execution_id)
{
	FInworldInputStreamTransformer* InputStreamTransformer = static_cast<FInworldInputStreamTransformer*>(opaque_this);
	if (InputStreamTransformer == nullptr)
	{
		UE_LOG(LogInworldGraph, Error, TEXT("FInworldInputStreamTransformer::transformCallback - Transformer is null"))
		inworld::TransformationStreamThreadedTransformExecutor_string_To_string::SetOutput(execution_id, std::string(""));
		return;
	}

	inworld::StatusOr_string status_or_string =
		inworld::TransformationStreamThreadedTransformExecutor_string_To_string::GetInput(execution_id);
	if (status_or_string.ok())
	{
		std::string transformed_string = InputStreamTransformer->transform(status_or_string.value());
		inworld::TransformationStreamThreadedTransformExecutor_string_To_string::SetOutput(execution_id, transformed_string);
	}
	else
	{
		UE_LOG(LogInworldGraph, Error, TEXT("FInworldInputStreamTransformer::transformCallback - Failed to get input string"))
		inworld::TransformationStreamThreadedTransformExecutor_string_To_string::SetOutput(execution_id, std::string(""));
	}
}

void FInworldInputStreamTransformer::destructorCallback(void* opaque_this)
{
	FInworldInputStreamTransformer* InputStreamTransformer{static_cast<FInworldInputStreamTransformer*>(opaque_this)};
	delete InputStreamTransformer;
}

FInworldData_DataStream_String FInworldInputStreamTransformer::WrapDataStream(
	const FInworldData_DataStream_String& Input, FInworldInputStreamTransformer* InputStreamTransformer)
{
	inworld::TransformationStreamThreadedTransformExecutor_string_To_string executor(
		InputStreamTransformer, (void*) &transformCallback);
	inworld::TransformationStreamDestructor destructor(InputStreamTransformer, (void*) &destructorCallback);

	inworld::StatusOr_InputStream_string status_or_input_stream_string =
		inworld::TransformationStream_string_To_string::Create(*Input.InputStream.Get(), executor, destructor);

	if (status_or_input_stream_string.ok())
	{
		inworld::DataStream_String datastream_string{status_or_input_stream_string.value()};
		return FInworldData_DataStream_String({datastream_string});
	}

	destructorCallback(InputStreamTransformer);
	return FInworldData_DataStream_String(Input);
}
