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

#pragma once

#include "CoreMinimal.h"
#include "Misc/TVariant.h"
#include "Primitives/Intent/InworldIntentTypes.h"
#include "Primitives/KeywordMatcher/InworldKeywordMatcherTypes.h"
#include "Primitives/LLM/InworldLLMTypes.h"
#include "Primitives/TTS/InworldTTSTypes.h"
#include "Templates/SharedPointer.h"

#include <string>

#include "InworldData.generated.h"

class UInworldNode;
class UInworldGraph;

struct FInworldData;

/**
 * @struct FInworldData_Bool
 * @brief Represents a boolean data type for graph processing.
 *
 * This structure encapsulates a boolean value for use within the Inworld graph system,
 * providing a standardized way to pass boolean data between nodes.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Bool
{
	GENERATED_BODY()

	/** The boolean value stored in this data structure */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The boolean value stored in this data structure"))
	bool Bool{false};
};

/**
 * @struct FInworldData_Int
 * @brief Represents an integer data type for graph processing.
 *
 * This structure encapsulates a 32-bit signed integer value for use within the Inworld
 * graph system, providing a standardized way to pass integer data between nodes.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Int
{
	GENERATED_BODY()

	/** The integer value stored in this data structure */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The integer value stored in this data structure"))
	int32 Int{0};
};

/**
 * @struct FInworldData_Float
 * @brief Represents a floating-point data type for graph processing.
 *
 * This structure encapsulates a single-precision floating-point value for use within
 * the Inworld graph system, providing a standardized way to pass numeric data between nodes.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Float
{
	GENERATED_BODY()

	/** The floating-point value stored in this data structure */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The floating-point value stored in this data structure"))
	float Float{0.f};
};

/**
 * @struct FInworldData_Object
 * @brief Represents an Unreal Engine object reference for graph processing.
 *
 * This structure encapsulates a reference to any UObject-derived object for use within
 * the Inworld graph system, enabling nodes to pass complex object references between each other.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Object
{
	GENERATED_BODY()

	/** The object reference stored in this data structure */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The object reference stored in this data structure"))
	TObjectPtr<UObject> Object{nullptr};
};

/**
 * @class FInworldDataHandle
 * @brief Smart handle for managing Inworld data objects.
 *
 * Provides a safe way to handle and access Inworld data objects with validity checking
 * and type casting capabilities. Acts as a wrapper around shared pointers to FInworldData
 * instances with additional type safety features.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldDataHandle
{
	GENERATED_BODY()

public:
	FInworldDataHandle() = default;
	FInworldDataHandle(const FInworldDataHandle& Other)
	{
		Data = Other.Data;
	}
	template <typename T, typename = std::enable_if_t<std::is_base_of_v<FInworldData, T> && !std::is_same_v<T, FInworldData>>>
	FInworldDataHandle(const T& InData)
	{
		Data = MakeShared<T>(InData);
	}

	FInworldDataHandle(FInworldData_Bool Bool);
	FInworldDataHandle(FInworldData_Int Int);
	FInworldDataHandle(FInworldData_Float Float);
	FInworldDataHandle(FInworldData_Object Object);

	[[nodiscard]] FORCEINLINE bool IsValid() const
	{
		return Data.IsValid();
	}

	[[nodiscard]] FORCEINLINE FInworldData* operator*() const
	{
		return Data.Get();
	}

	[[nodiscard]] FORCEINLINE FInworldData* operator->() const
	{
		return Data.Get();
	}

	template <typename T>
	bool IsA() const;

	template <typename T>
	T* Unwrap() const;

	TSharedPtr<FInworldData> Data{nullptr};
};

/**
 * @class FInworldDataHandle_Stream
 * @brief Smart handle for managing streamed Inworld data.
 *
 * An extended FInworldDataHandle for streamed data objects with additional information on the index of the data in the stream
 * and whether this was the last item in the stream.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldDataHandle_Stream : public FInworldDataHandle
{
	GENERATED_BODY()

public:
	/* The index of the item in the stream */
	int32 Index{0};

	/* Whether this is the last data item in the stream. */
	bool IsFinal{false};
};

namespace inworld
{
class DataStream_String;
class CustomDataWrapper;
class NodeWrapper;
class BaseData;
class vector_Event;
class vector_string;
class InputStream_Content;
class InputStream_string;
class InputStream_TTSOutput;
class InputStream_AudioChunk;
class BlockingStream_AudioChunk;
class MemorySnapshot;
}	 // namespace inworld

#ifndef INWORLD_DATA
#define INWORLD_DATA(Name)                                                               \
	virtual UScriptStruct* GetScriptStruct() const override                              \
	{                                                                                    \
		return FInworldData_##Name::StaticStruct();                                      \
	}                                                                                    \
	virtual bool IsA(UScriptStruct* Type) const override                                 \
	{                                                                                    \
		return Super::IsA(Type) || FInworldData_##Name::StaticStruct() == Type;          \
	}                                                                                    \
	virtual FInworldDataHandle Wrap() override                                           \
	{                                                                                    \
		return FInworldData_##Name(MoveTemp(*this));                                     \
	}                                                                                    \
	static FInworldData_##Name Error(const FString& Reason)                              \
	{                                                                                    \
		return FInworldData::ErrorTypeFactory::CreateError<FInworldData_##Name>(Reason); \
	}
#endif

/**
 * @class FInworldData
 * @brief Represents the base interface for all data types in the workflow
 * system.
 *
 * This abstract structure defines the common interface that all data types must
 * implement, providing a foundation for polymorphic operations on different
 * types of data within the workflow system.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData
{
	GENERATED_BODY()
public:
	FInworldData() = default;
	virtual ~FInworldData() = default;

	virtual UScriptStruct* GetScriptStruct() const;
	virtual bool IsA(UScriptStruct* Type) const;
	virtual FInworldDataHandle Wrap();
	virtual inworld::BaseData* CreateRuntimeData();

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() PURE_VIRTUAL(FInworldData::CreateRuntimeData_Internal, return nullptr;);

	struct ErrorTypeFactory
	{
		template <typename T>
		static T CreateError(const FString& Reason)
		{
			T Instance;
			Instance.ErrorInfo = Reason;
			return Instance;
		}
	};
	friend struct ErrorTypeFactory;
	friend class UInworldBlueprintFunctionLibrary;

private:
	TOptional<TTuple<FString>> ErrorInfo{};
};

/**
 * @struct FInworldData_Struct
 * @brief Represents arbitrary struct data for graph processing.
 *
 * This structure provides a way to encapsulate any Unreal Engine struct (USTRUCT)
 * for use within the Inworld graph system. It uses type-erased storage to hold
 * struct data of any type, making it useful for passing complex data structures
 * between nodes while maintaining type safety through templated constructors.
 */
USTRUCT()
struct INWORLDRUNTIME_API FInworldData_Struct final : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(Struct)
public:
	FInworldData_Struct() = default;
	FInworldData_Struct(const FInworldData_Struct& Other);
	FInworldData_Struct(UScriptStruct* ScriptStruct, const void* Data);
	template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T> && !std::is_base_of_v<FInworldData, std::decay_t<T>>>>
	FInworldData_Struct(const T& Data) : FInworldData_Struct(std::decay_t<T>::StaticStruct(), &Data)
	{
	}
	FInworldData_Struct(void* InBlob);
	virtual ~FInworldData_Struct();

	template <typename T, typename = std::enable_if_t<!std::is_base_of_v<FInworldData, T>>>
	bool GetData(T& OutData) const
	{
		if (T::StaticStruct() != GetDataScriptStruct())
		{
			return false;
		}
		GetDataScriptStruct()->CopyScriptStruct(&OutData, GetData());
		return true;
	}

	uint64 GetSize() const;
	UScriptStruct* GetDataScriptStruct() const;
	void* GetData() const;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;

private:
	void* Blob{nullptr};
};

/**
 * @class FInworldData_Error
 * @brief Represents an error with status information.
 *
 * This class encapsulates error information, providing detailed error reporting within the workflow system.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Error : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(Error)

public:
	FInworldData_Error() = default;
	FInworldData_Error(const FString& InReason) : Reason(InReason){};
	FInworldData_Error(const inworld::BaseData& Data);
	virtual ~FInworldData_Error() = default;

	/** The reason or description of the error that occurred */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The reason or description of the error that occurred"))
	FString Reason{};

	/** Whether the operation completed successfully (false indicates an error occurred) */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Whether the operation completed successfully (false indicates an error occurred)"))
	bool bOk{false};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_Text
 * @brief Represents a simple text data type.
 *
 * This class encapsulates string data for processing within the workflow
 * system.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Text : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(Text)

public:
	FInworldData_Text() = default;
	FInworldData_Text(const FString& InText) : Text(InText){};
	FInworldData_Text(const inworld::BaseData& Data);
	virtual ~FInworldData_Text() = default;

	/** The text content stored in this data structure */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The text content stored in this data structure"))
	FString Text{};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_LLMChatRequest
 * @brief Represents messages used by LLM
 *
 * This class encapsulates role & string data  for processing within the workflow
 * system.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_LLMChatRequest : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(LLMChatRequest)

public:
	FInworldData_LLMChatRequest() = default;
	FInworldData_LLMChatRequest(const TArray<FInworldLLMMessage>& InChatMessages,
		EInworldLLMResponseFormat InResponseFormat = EInworldLLMResponseFormat::TEXT)
		: ChatMessages(InChatMessages), ResponseFormat(InResponseFormat){};
	FInworldData_LLMChatRequest(const inworld::BaseData& Data);
	virtual ~FInworldData_LLMChatRequest() = default;

	/** Array of chat messages that form the conversation context for the LLM */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Array of chat messages that form the conversation context for the LLM"))
	TArray<FInworldLLMMessage> ChatMessages{};

	/** The desired response format from the LLM (text, JSON, or JSON with schema) */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The desired response format from the LLM (text, JSON, or JSON with schema)"))
	EInworldLLMResponseFormat ResponseFormat{EInworldLLMResponseFormat::TEXT};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_Audio
 * @brief Represents audio data with waveform and sample rate information.
 *
 * This class encapsulates audio data, including both the waveform samples
 * and the sample rate, for audio processing operations.
 */
USTRUCT(BlueprintType, meta = (HasNativeMake = "/Script/InworldRuntime.InworldBlueprintFunctionLibrary:MakeAudio",
						   HasNativeBreak = "/Script/InworldRuntime.InworldBlueprintFunctionLibrary:BreakAudio"))
struct INWORLDRUNTIME_API FInworldData_Audio : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(Audio)

public:
	FInworldData_Audio() = default;
	FInworldData_Audio(const TArray<uint8>& InWaveform, int32 InSampleRate)
		: Waveform(MakeShared<TArray<uint8>>(InWaveform)), SampleRate(InSampleRate){};
	FInworldData_Audio(const TSharedPtr<TArray<uint8>>& InWaveform, int32 InSampleRate)
		: Waveform(InWaveform), SampleRate(InSampleRate){};

	FInworldData_Audio(const inworld::BaseData& Data);
	virtual ~FInworldData_Audio() = default;

	/** Shared pointer to the audio waveform data as a byte array */
	TSharedPtr<TArray<uint8>> Waveform{MakeShared<TArray<uint8>>()};

	/** The sample rate of the audio data in Hz */
	UPROPERTY(
		EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph", Meta = (ToolTip = "The sample rate of the audio data in Hz"))
	int32 SampleRate{0};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_SafetyResult
 * @brief Represents a safety check result.
 *
 * This class encapsulates the result of a safety check, indicating whether
 * certain content is considered safe for processing. Contains the checked
 * text as well.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_SafetyResult : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(SafetyResult)

public:
	FInworldData_SafetyResult() = default;
	FInworldData_SafetyResult(bool bInIsSafe, const FString& InText) : bIsSafe(bInIsSafe), Text(InText){};
	FInworldData_SafetyResult(const inworld::BaseData& Data);
	virtual ~FInworldData_SafetyResult() = default;

	/** Whether the content passed the safety check and is considered safe */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Whether the content passed the safety check and is considered safe"))
	bool bIsSafe{true};

	/** The text content that was evaluated for safety */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "The text content that was evaluated for safety"))
	FString Text;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_KnowledgeRecords
 * @brief Represents a collection of knowledge records as strings.
 *
 * This class stores multiple knowledge records that can be used for
 * information retrieval or other knowledge-based operations.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_KnowledgeRecords : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(KnowledgeRecords)

public:
	FInworldData_KnowledgeRecords() = default;
	FInworldData_KnowledgeRecords(const TArray<FString>& InRecords) : Records(InRecords){};
	FInworldData_KnowledgeRecords(const inworld::BaseData& Data);
	virtual ~FInworldData_KnowledgeRecords() = default;

	/** Array of knowledge records as text strings */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Array of knowledge records as text strings"))
	TArray<FString> Records{};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_ClassificationResult
 * @brief Represents the result of text classification operations.
 *
 * This class encapsulates the result from text classification, containing
 * information about the classes that were detected.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_ClassificationResult : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(ClassificationResult)

public:
	FInworldData_ClassificationResult() = default;
	FInworldData_ClassificationResult(const TArray<FString>& InClasses) : Classes(InClasses){};
	FInworldData_ClassificationResult(const inworld::BaseData& Data);
	virtual ~FInworldData_ClassificationResult() = default;

	/** Array of classification results indicating which classes were detected */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Array of classification results indicating which classes were detected"))
	TArray<FString> Classes{};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_MatchedKeywords
 * @brief Represents the result of keyword matching operations.
 *
 * This class encapsulates the result from keyword matching, containing
 * information about matched keywords and their associated groups.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_MatchedKeywords : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(MatchedKeywords)

public:
	FInworldData_MatchedKeywords() = default;
	FInworldData_MatchedKeywords(const TArray<FInworldKeywordMatch>& InMatches) : Matches(InMatches){};
	FInworldData_MatchedKeywords(const inworld::BaseData& Data);
	virtual ~FInworldData_MatchedKeywords() = default;

	/** Array of matched keywords with their associated group information */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Array of matched keywords with their associated group information"))
	TArray<FInworldKeywordMatch> Matches{};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_MatchedIntents
 * @brief Represents the result of intent matching containing the matched
 * intents with scores.
 *
 * This class stores the results of intent matching operations, including
 * a collection of matched intents with their confidence scores.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_MatchedIntents : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(MatchedIntents)

public:
	FInworldData_MatchedIntents() = default;
	FInworldData_MatchedIntents(const inworld::BaseData& Data);
	virtual ~FInworldData_MatchedIntents() = default;

	/** Array of matched intents with their confidence scores */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Array of matched intents with their confidence scores"))
	TArray<FInworldIntentMatch> IntentMatches{};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_TTSOutput
 * @brief Represents TTSOutput data combining audio, text, and viseme information.
 *
 * This class encapsulates voice-related data including the audio waveform,
 * corresponding text transcription, and viseme information for lip-sync
 * animation. It provides a complete package of information needed for
 * voice-based interactions and animations.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_TTSOutput : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(TTSOutput)

public:
	FInworldData_TTSOutput() = default;
	FInworldData_TTSOutput(const inworld::BaseData& Data);
	virtual ~FInworldData_TTSOutput() = default;

	/** The synthesized audio data from text-to-speech processing */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Graph",
		Meta = (ToolTip = "The synthesized audio data from text-to-speech processing"))
	FInworldData_Audio Audio{};

	/** The text that was synthesized into speech */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Graph", Meta = (ToolTip = "The text that was synthesized into speech"))
	FString Text{};

	/** Array of viseme information for lip-sync animation timing */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Audio",
		Meta = (ToolTip = "Array of viseme information for lip-sync animation timing"))
	TArray<FInworldVisemeInfo> VisemeInfos{};

	/** Whether this is the final chunk in a streaming TTS response */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Audio",
		Meta = (ToolTip = "Whether this is the final chunk in a streaming TTS response"))
	bool bIsFinal{false};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_EventHistory
 * @brief Represents the history of events in agent workflow.
 *
 * This class encapsulates the history of events that have occurred during the
 * execution of an agent workflow, including interactions and other relevant
 * actions.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_EventHistory : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(EventHistory)

public:
	FInworldData_EventHistory() = default;
	FInworldData_EventHistory(const inworld::BaseData& Data);
	virtual ~FInworldData_EventHistory() = default;

	/** Shared pointer to the internal event history vector for native processing */
	TSharedPtr<inworld::vector_Event> EventHistory;

	/** Array of speech events extracted from the event history for Blueprint access */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Graph",
		Meta = (ToolTip = "Array of speech events extracted from the event history for Blueprint access"))
	TArray<FInworldEventSpeech> SpeechEvents;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_Json
 * @brief Represents the Json data type.
 *
 * This class encapsulates Json data for processing within the workflow
 * system.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Json : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(Json)

public:
	FInworldData_Json() = default;
	FInworldData_Json(const inworld::BaseData& Data);
	virtual ~FInworldData_Json() = default;

	/** The JSON data as a string */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Graph", Meta = (ToolTip = "The JSON data as a string"))
	FString JsonString;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

#ifndef INWORLD_DATA_STREAM
#define INWORLD_DATA_STREAM(Type)                  \
	INWORLD_DATA(DataStream_##Type)                \
	virtual bool HasNext() const override;         \
	virtual FInworldDataHandle GetNext() override; \
	TSharedPtr<inworld::InputStream_##Type> InputStream;
#endif

/**
 * @class FInworldData_Stream
 * @brief Base class for streamed data in the workflow system.
 *
 * This abstract class provides the foundation for different types of data streams,
 * defining the interface for iterating through sequential data with HasNext and GetNext operations.
 *
 * Example:
 * FInworldData OutputData = {...};
 * ...
 * if (FInworldData_Stream * Stream{OutputData.Unwrap<FInworldData_Stream>()}; Stream != nullptr)
 * {
 *		while (Stream->HasNext())
 *		{
 *			FInworldDataHandle OutputChunk = Stream->GetNext();
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_Stream : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(Stream)

public:
	FInworldData_Stream() = default;
	virtual ~FInworldData_Stream() = default;

	/**
	 * @brief Checks if there are more data items available in the stream.
	 *
	 * This pure virtual function must be implemented by derived stream classes
	 * to indicate whether additional data chunks are available for retrieval.
	 *
	 * @return True if more data is available, false if the stream is exhausted
	 */
	virtual bool HasNext() const PURE_VIRTUAL(FInworldData::HasNext, return false;);

	/**
	 * @brief Retrieves the next data item from the stream.
	 *
	 * This function advances the stream and returns the next available data chunk.
	 * Should only be called when HasNext() returns true. The behavior when called
	 * on an exhausted stream is implementation-dependent.
	 *
	 * @return Handle to the next data item in the stream
	 */
	virtual FInworldDataHandle GetNext();
};

/**
 * @class FInworldData_LLMChatResponse
 * @brief Represents messages returned by LLM
 *
 * This class encapsulates llm output content.
 * Object may or may not be streamed.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_LLMChatResponse : public FInworldData_Stream
{
	GENERATED_BODY()
	INWORLD_DATA(LLMChatResponse)

public:
	FInworldData_LLMChatResponse() = default;
	FInworldData_LLMChatResponse(const inworld::BaseData& Data);
	virtual ~FInworldData_LLMChatResponse() = default;

	/** The content of the LLM response message */
	UPROPERTY(
		EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph", Meta = (ToolTip = "The content of the LLM response message"))
	FString Content{};

	/** Whether this response is part of a streaming response */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Graph",
		Meta = (ToolTip = "Whether this response is part of a streaming response"))
	bool bIsStreaming{};

	virtual bool HasNext() const override;
	virtual FInworldDataHandle GetNext() override;

	/** Shared pointer to the internal content input stream for streaming LLM responses */
	TSharedPtr<inworld::InputStream_Content> InputStream;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

namespace inworld
{
using InputStream_String = InputStream_string;
}

/**
 * @class FInworldData_DataStream_String
 * @brief Implements a stream of string data.
 *
 * Provides sequential access to a stream of string values, allowing iteration
 * through text-based data in a controlled manner.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_DataStream_String : public FInworldData_Stream
{
	GENERATED_BODY()
	INWORLD_DATA_STREAM(String)

public:
	FInworldData_DataStream_String() = default;
	FInworldData_DataStream_String(const inworld::BaseData& Data);
	virtual ~FInworldData_DataStream_String() = default;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @class FInworldData_DataStream_TTSOutput
 * @brief Implements a stream of Text-to-Speech output data.
 *
 * Provides sequential access to TTS output data, allowing controlled iteration
 * through generated speech data for processing or playback.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_DataStream_TTSOutput : public FInworldData_Stream
{
	GENERATED_BODY()
	INWORLD_DATA_STREAM(TTSOutput)

public:
	FInworldData_DataStream_TTSOutput() = default;
	FInworldData_DataStream_TTSOutput(const inworld::BaseData& Data);
	virtual ~FInworldData_DataStream_TTSOutput() = default;

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

#undef INWORLD_DATA_STREAM

template <typename T>
inline bool FInworldDataHandle::IsA() const
{
	return IsValid() ? Data->IsA(T::StaticStruct()) : false;
}

template <typename T>
inline T* FInworldDataHandle::Unwrap() const
{
	return IsA<T>() ? static_cast<T*>(**this) : nullptr;
}

/**
 * @class FInworldData_TTSRequest
 * @brief Represents TTSRequest
 *
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_TTSRequest : public FInworldData_Stream
{
	GENERATED_BODY()
	INWORLD_DATA(TTSRequest)

public:
	FInworldData_TTSRequest() = default;
	FInworldData_TTSRequest(const inworld::BaseData& Data);
	virtual ~FInworldData_TTSRequest() = default;

	/** Whether this TTS request contains static text content */
	UPROPERTY(
		BlueprintReadOnly, Category = "Inworld|Graph", Meta = (ToolTip = "Whether this TTS request contains static text content"))
	bool bHasTextContent{false};

	/** The static text content to be synthesized */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Graph", Meta = (ToolTip = "The static text content to be synthesized"))
	FString Text{};

	/** Whether this TTS request contains streaming content */
	UPROPERTY(
		BlueprintReadOnly, Category = "Inworld|Graph", Meta = (ToolTip = "Whether this TTS request contains streaming content"))
	bool bHasStreamContent{false};

	virtual bool HasNext() const override;
	virtual FInworldDataHandle GetNext() override;

	/** Shared pointer to the internal string input stream for streaming text content */
	TSharedPtr<inworld::InputStream_string> InputStream;

	/** The voice configuration to use for text-to-speech synthesis */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Graph",
		Meta = (ToolTip = "The voice configuration to use for text-to-speech synthesis"))
	FInworldVoice Voice{};

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;
};

/**
 * @struct FInworldData_DataStream_AudioChunk
 * @brief Represents a writable audio data stream for processing audio chunks.
 *
 * This structure provides a way to write audio data in chunks for streaming audio
 * processing within the Inworld graph system. It supports both input and blocking
 * stream types for different audio processing scenarios.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldData_DataStream_AudioChunk : public FInworldData
{
	GENERATED_BODY()
	INWORLD_DATA(DataStream_AudioChunk)

public:
	FInworldData_DataStream_AudioChunk();
	FInworldData_DataStream_AudioChunk(const inworld::BaseData& Data);
	virtual ~FInworldData_DataStream_AudioChunk() = default;

#if WITH_EDITOR && !UE_BUILD_SHIPPING
	/**
	 * @brief Sets the debug dump file name for audio stream debugging.
	 * @param InDebugDumpFileName The file name for debug output
	 */
	void SetDebugDumpFileName(const FString& InDebugDumpFileName);
#endif

	/**
	 * @brief Writes audio data to the stream.
	 * @param Audio The audio data to write to the stream
	 */
	void Write(const FInworldData_Audio& Audio);

	/**
	 * @brief Closes the audio stream, finalizing any pending operations.
	 */
	void Close();

protected:
	virtual inworld::BaseData* CreateRuntimeData_Internal() override;

private:
	TVariant<TSharedPtr<inworld::InputStream_AudioChunk>, TSharedPtr<inworld::BlockingStream_AudioChunk>> Stream{};
#if WITH_EDITOR && !UE_BUILD_SHIPPING
	TOptional<FString> DebugDumpFileName{};
#endif
};
