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

#pragma once

#include "CoreMinimal.h"
#include "Engine/DataTable.h"

#include "InworldRuntimeTypes.generated.h"

/**
 * @enum EInworldComputeHost
 * @brief Enumeration for specifying where computation should be executed.
 */
UENUM(BlueprintType)
enum class EInworldComputeHost : uint8
{
	/** Computation will execute on the local device */
	LOCAL,

	/** Computation will execute remotely on cloud servers */
	REMOTE,
};

/**
 * @enum EInworldLocalComputeHost
 * @brief Enumeration for specifying local computation device type.
 */
UENUM(BlueprintType)
enum class EInworldLocalComputeHost : uint8
{
	/** Computation will execute on the CPU */
	CPU,

	/** Computation will execute on the CUDA/METAL compatible graphics card */
	GPU,
};

/**
 * @enum EInworldRuntimeDevice
 * @brief Enumeration for runtime device selection (deprecated, use EInworldComputeHost instead).
 * TODO: replace 'FrameworkDevice' with 'ComputeHost'
 */
UENUM(BlueprintType)
enum class EInworldRuntimeDevice : uint8
{
	/** Computation will execute on the CPU */
	CPU,

	/** Computation will execute on the CUDA compatible graphics card (or on METAL if on a Mac) */
	CUDA_GPU,

	/** Computation will execute on a Inworld Cloud Server (requires API Key) */
	CLOUD
};

/**
 * @enum EInworldLanguage
 * @brief Enumeration of supported languages for Inworld AI services.
 */
UENUM(BlueprintType)
enum class EInworldLanguage : uint8
{
	ARABIC UMETA(DisplayName = "Arabic"),
	CHINESE UMETA(DisplayName = "Chinese"),
	DANISH UMETA(DisplayName = "Danish"),
	DUTCH UMETA(DisplayName = "Dutch"),
	ENGLISH UMETA(DisplayName = "English"),
	FINNISH UMETA(DisplayName = "Finnish"),
	FRENCH UMETA(DisplayName = "French"),
	GERMAN UMETA(DisplayName = "German"),
	HEBREW UMETA(DisplayName = "Hebrew"),
	HINDI UMETA(DisplayName = "Hindi"),
	INDONESIAN UMETA(DisplayName = "Indonesian"),
	ITALIAN UMETA(DisplayName = "Italian"),
	JAPANESE UMETA(DisplayName = "Japanese"),
	KOREAN UMETA(DisplayName = "Korean"),
	MALAY UMETA(DisplayName = "Malay"),
	NORWEGIAN UMETA(DisplayName = "Norwegian"),
	POLISH UMETA(DisplayName = "Polish"),
	PORTUGUESE UMETA(DisplayName = "Portuguese"),
	RUSSIAN UMETA(DisplayName = "Russian"),
	SPANISH UMETA(DisplayName = "Spanish"),
	SWEDISH UMETA(DisplayName = "Swedish"),
	THAI UMETA(DisplayName = "Thai"),
	TURKISH UMETA(DisplayName = "Turkish"),
	UKRAINIAN UMETA(DisplayName = "Ukrainian"),
	VIETNAMESE UMETA(DisplayName = "Vietnamese"),
};

/**
 * @enum EInworldViseme
 * @brief Enumeration of viseme types for lip-sync animation.
 *
 * Visemes represent the visual mouth shapes that correspond to phonemes for
 * creating realistic lip-sync animations with synthesized speech.
 */
UENUM(BlueprintType)
enum class EInworldViseme : uint8
{
	PP UMETA(DisplayName = "PP"),
	FF UMETA(DisplayName = "FF"),
	TH UMETA(DisplayName = "TH"),
	DD UMETA(DisplayName = "DD"),
	KK UMETA(DisplayName = "kk"),
	CH UMETA(DisplayName = "CH"),
	SS UMETA(DisplayName = "SS"),
	NN UMETA(DisplayName = "nn"),
	RR UMETA(DisplayName = "RR"),
	AA UMETA(DisplayName = "aa"),
	E UMETA(DisplayName = "E"),
	I UMETA(DisplayName = "I"),
	O UMETA(DisplayName = "O"),
	U UMETA(DisplayName = "U"),
	STOP UMETA(DisplayName = "STOP")
};

/**
 * @struct FInworldGraphFeedback
 * @brief Structure for providing user feedback on graph execution results.
 *
 * This structure encapsulates feedback data that can be sent to improve
 * the Inworld AI system through telemetry and usage analytics.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldGraphFeedback
{
	GENERATED_BODY()

	/** The identifier of the graph that generated this feedback */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Inworld|Text",
		Meta = (ToolTip = "The identifier of the graph that generated this feedback"))
	FString GraphId{""};

	/** The execution instance identifier that received this feedback */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Inworld|Text",
		Meta = (ToolTip = "The execution instance identifier that received this feedback"))
	FString ExecutionId{""};

	/** Numerical rating for the execution result */
	UPROPERTY(
		BlueprintReadWrite, EditAnywhere, Category = "Inworld|Text", Meta = (ToolTip = "Numerical rating for the execution result"))
	int32 Rating = 0;

	/** Textual description or comment about the execution */
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Inworld|Text",
		Meta = (ToolTip = "Textual description or comment about the execution"))
	FString Description{""};
};

/**
 * @struct FInworldNodeHistory
 * @brief Structure containing execution history information for a single node.
 *
 * This structure captures detailed execution metrics and data for individual
 * nodes during graph execution, used for debugging and performance analysis.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldNodeHistory
{
	GENERATED_BODY()

	/** The unique identifier for this execution span */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "The unique identifier for this execution span"))
	FString SpanId{""};

	/** The identifier of the parent span that contains this span */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "The identifier of the parent span that contains this span"))
	FString ParentSpanId{""};

	/** The name of this node */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History", Meta = (ToolTip = "The name of this node"))
	FString Name{""};

	/** JSON string representation of the node's data store */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "JSON string representation of the node's data store"))
	FString DataStoreAsJson{""};

	/** JSON string representation of the node's output */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "JSON string representation of the node's output"))
	FString OutputAsJson{""};

	/** Unix timestamp in nanoseconds when execution started */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "Unix timestamp in nanoseconds when execution started"))
	int64 StartTime{0};

	/** Execution duration in nanoseconds */
	UPROPERTY(
		BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History", Meta = (ToolTip = "Execution duration in nanoseconds"))
	int64 Duration{0};

	/** Execution duration converted to milliseconds for convenience */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "Execution duration converted to milliseconds for convenience"))
	double DurationInMilliSeconds{0.f};

	bool operator==(const FString& OtherName) const
	{
		return Name.Compare(OtherName, ESearchCase::IgnoreCase) == 0;
	}

	bool operator<(const FInworldNodeHistory& Other) const
	{
		return StartTime < Other.StartTime;
	}
};

USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldGraphExecutionHistory
{
	GENERATED_BODY()

	/** The identifier of the graph that was executed */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "The identifier of the graph that was executed"))
	FString GraphId{""};

	/** The unique identifier for this specific execution instance */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "The unique identifier for this specific execution instance"))
	FString ExecutionId{""};

	/** Array of execution history for each node that ran during this graph execution */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "Array of execution history for each node that ran during this graph execution"))
	TArray<FInworldNodeHistory> NodeHistory;

	/** The owner object of this execution, as determined via runtime data */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "The owner object of this execution, as determined via runtime data"))
	TWeakObjectPtr<UObject> Owner;

	/** The name of the owner (kept as backup once the Owner becomes stale/unloaded) */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "The name of the owner (kept as backup once the Owner becomes stale/unloaded)"))
	FString OwnerName;

	/** List of error messages that occurred during this execution */
	UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Inworld|History",
		Meta = (ToolTip = "List of error messages that occurred during this execution"))
	TArray<FString> ErrorList;

	void AddError(const FString& ErrorMessage);

	const FString GetLastError() const;
	const FInworldNodeHistory* GetLastNode() const;
	const FInworldNodeHistory* GetSlowestNode() const;

	bool operator==(const FString& OtherExecId) const
	{
		return ExecutionId.Compare(OtherExecId, ESearchCase::IgnoreCase) == 0;
	}
};

/**
 * @struct FInworldStringChunk
 * @brief Structure representing a chunk of text with its index in a sequence.
 *
 * This structure is used for processing text in chunks, particularly useful
 * for streaming text operations where text is processed incrementally.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldStringChunk
{
	GENERATED_BODY()

public:
	/** The text content of this chunk */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|Text", Meta = (ToolTip = "The text content of this chunk"))
	FString Chunk{""};

	/** The index of this chunk in the sequence */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|Text", Meta = (ToolTip = "The index of this chunk in the sequence"))
	int32 Index{INDEX_NONE};
};

/**
 * @struct FInworldVisemeInfo
 * @brief Structure containing viseme timing information for lip-sync animation.
 *
 * This structure pairs a viseme code with its timestamp, used to create
 * accurate lip-sync animations that match synthesized speech timing.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldVisemeInfo
{
	GENERATED_BODY()

public:
	/** The viseme code indicating the mouth shape */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Audio", Meta = (ToolTip = "The viseme code indicating the mouth shape"))
	FString Code;

	/** The timestamp in seconds when this viseme should be displayed */
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Audio",
		Meta = (ToolTip = "The timestamp in seconds when this viseme should be displayed"))
	float Timestamp = 0.f;
};

USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldEventSpeech
{
	GENERATED_BODY()

public:
	/** The name of the agent who spoke */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|Event", Meta = (ToolTip = "The name of the agent who spoke"))
	FString AgentName{};

	/** The text content of what was said */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|Event", Meta = (ToolTip = "The text content of what was said"))
	FString Utterance{};
};

USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldHistoryEventData
{
	GENERATED_BODY()

	/** Array of speech events in the conversation history */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Event",
		Meta = (ToolTip = "Array of speech events in the conversation history"))
	TArray<FInworldEventSpeech> SpeechEvents;
};

USTRUCT()
struct INWORLDRUNTIME_API FInworldEventHistoryEntry : public FTableRowBase
{
	GENERATED_BODY()

	/** The name of the agent who spoke */
	UPROPERTY(EditAnywhere, BlueprintReadOnly,
		Category = "Who",	 // Keep this category name as single, otherwise breaks table edit
		Meta = (ToolTip = "The name of the agent who spoke"))
	FString AgentName{};

	/** The text content of what was said */
	UPROPERTY(EditAnywhere, BlueprintReadOnly,
		Category = "Speech",	// Keep this category name as single, otherwise breaks table edit
		Meta = (ToolTip = "The text content of what was said"))
	FString Utterance{};
};

USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldKnowledgeData
{
	GENERATED_BODY()

	TArray<TSharedPtr<const TArray<struct FInworldTextEmbedding>>> TextEmbeddings;

	/** Array of text embedding assets used for knowledge retrieval */
	UPROPERTY(
		BlueprintReadOnly, Category = "Knowledge", Meta = (ToolTip = "Array of text embedding assets used for knowledge retrieval"))
	TArray<const class UInworldTextEmbeddingAsset*> TextEmbeddingAssets;
};

USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldMemoryData
{
	GENERATED_BODY()

	/** Array of memory record strings */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Data", Meta = (ToolTip = "Array of memory record strings"))
	TArray<FString> Records;
};

USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldVisemeBlends
{
	GENERATED_BODY()

public:
	/** Viseme blend value for the PP viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the PP viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float PP = 0.f;

	/** Viseme blend value for the FF viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the FF viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float FF = 0.f;

	/** Viseme blend value for the TH viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the TH viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float TH = 0.f;

	/** Viseme blend value for the DD viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the DD viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float DD = 0.f;

	/** Viseme blend value for the Kk viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the Kk viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float Kk = 0.f;

	/** Viseme blend value for the CH viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the CH viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float CH = 0.f;

	/** Viseme blend value for the SS viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the SS viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float SS = 0.f;

	/** Viseme blend value for the Nn viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the Nn viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float Nn = 0.f;

	/** Viseme blend value for the RR viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the RR viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float RR = 0.f;

	/** Viseme blend value for the Aa viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the Aa viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float Aa = 0.f;

	/** Viseme blend value for the E viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the E viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float E = 0.f;

	/** Viseme blend value for the I viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the I viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float I = 0.f;

	/** Viseme blend value for the O viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the O viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float O = 0.f;

	/** Viseme blend value for the U viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f, ToolTip = "Viseme blend value for the U viseme (0.0-1.0)"),
		Category = "Inworld|Viseme")
	float U = 0.f;

	/** Viseme blend value for the STOP viseme. */
	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly,
		meta = (ClampMin = 0.f, ClampMax = 1.f,
			ToolTip = "Viseme blend value for the STOP viseme (0.0-1.0) - represents mouth closed/rest state"),
		Category = "Inworld|Viseme")
	float STOP = 1.f;

public:
	float& operator[](const FName& Code)
	{
		return (*this)[Code.ToString()];
	};
	float& operator[](const FString& Code)
	{
		if (Code == "PP")
			return PP;
		else if (Code == "FF")
			return FF;
		else if (Code == "TH")
			return TH;
		else if (Code == "DD")
			return DD;
		else if (Code == "Kk")
			return Kk;
		else if (Code == "CH")
			return CH;
		else if (Code == "SS")
			return SS;
		else if (Code == "Nn")
			return Nn;
		else if (Code == "RR")
			return RR;
		else if (Code == "Aa")
			return Aa;
		else if (Code == "E")
			return E;
		else if (Code == "I")
			return I;
		else if (Code == "O")
			return O;
		else if (Code == "U")
			return U;
		else
			return STOP;
	};
};

namespace inworld
{
class Language;
void Convert(const EInworldLanguage& In, inworld::Language& Out);
void Convert(const inworld::Language& In, EInworldLanguage& Out);
void Convert(const EInworldLanguage& In, FString& Out);
}	 // namespace inworld

/**
 * @struct FInworldPlayerProfile
 * @brief Structure containing player profile information for character interactions.
 *
 * This structure defines player characteristics that can influence how AI characters
 * interact with and respond to the player in conversations and scenarios.
 */
USTRUCT(BlueprintType)
struct INWORLDRUNTIME_API FInworldPlayerProfile
{
	GENERATED_BODY()

	/** The player's name */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Player", Meta = (ToolTip = "The player's name"))
	FString Name;

	/** The player's gender identity */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Player", Meta = (ToolTip = "The player's gender identity"))
	FString Gender;

	/** The player's age or age range */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Player", Meta = (ToolTip = "The player's age or age range"))
	FString Age;

	/** The player's role or occupation in the scenario */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Player",
		Meta = (ToolTip = "The player's role or occupation in the scenario"))
	FString Role;
};

USTRUCT()
struct INWORLDRUNTIME_API FUnrealObjectInstance
{
	GENERATED_BODY()

	/** Serialized instance data as string */
	UPROPERTY(Meta = (ToolTip = "Serialized instance data as string"))
	FString InstanceData;
};

USTRUCT()
struct INWORLDRUNTIME_API FUnrealObjectCreationConfig
{
	GENERATED_BODY()

	/** Unique identifier for this object configuration */
	UPROPERTY(Meta = (ToolTip = "Unique identifier for this object configuration"))
	FString Id;

	/** Type of object to be created */
	UPROPERTY(Meta = (ToolTip = "Type of object to be created"))
	FString Type;

	/** Serialized instance data for object creation */
	UPROPERTY(Meta = (ToolTip = "Serialized instance data for object creation"))
	FString InstanceData;
};
