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

#pragma once

#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "Graph/InworldData.h"
#include "Primitives/Knowledge/InworldKnowledgeTypes.h"

#include "InworldCharacterTypes.generated.h"

/**
 * @struct FInworldCharacterProfile
 * @brief Complete profile definition for an Inworld character's personality and dialogue style.
 *
 * This structure defines all aspects of a character's identity, background, and speaking style
 * used by the AI system to generate consistent, character-appropriate responses.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldCharacterProfile
{
	GENERATED_BODY()

	/** The character's name as they introduce themselves and are referred to by others */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Details",
		Meta = (ToolTip = "The character's name as they introduce themselves and are referred to by others"))
	FString Name;

	/** The character's role or occupation in the game world (e.g., "Village Elder", "Shop Keeper") */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Details",
		Meta = (ToolTip = "The character's role or occupation in the game world (e.g., 'Village Elder', 'Shop Keeper')"))
	FString Role;

	/** The character's preferred pronouns (e.g., "he/him", "she/her", "they/them") */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Details",
		Meta = (ToolTip = "The character's preferred pronouns (e.g., 'he/him', 'she/her', 'they/them')"))
	FString Pronouns;

	/** The character's age range or life stage (e.g., "Young Adult", "Middle-aged", "Elderly") */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Details",
		Meta = (ToolTip = "The character's age range or life stage (e.g., 'Young Adult', 'Middle-aged', 'Elderly')"))
	FString StageOfLife;

	/** The character's interests, hobbies, and activities they enjoy or engage with */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Details",
		Meta = (ToolTip = "The character's interests, hobbies, and activities they enjoy or engage with"))
	FString HobbiesAndInterests;

	/** General description of the character's appearance, background, and defining characteristics */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character",
		Meta = (ToolTip = "General description of the character's appearance, background, and defining characteristics"))
	FString Description;

	/** What drives the character's actions and decisions; their goals and desires */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character",
		Meta = (ToolTip = "What drives the character's actions and decisions; their goals and desires"))
	FString Motivation;

	/** The character's weaknesses, negative traits, or imperfections that make them relatable */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character",
		Meta = (ToolTip = "The character's weaknesses, negative traits, or imperfections that make them relatable"))
	FString Flaws;

	/** Whether to use custom dialogue style configuration instead of a preset style */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Dialogue Style",
		Meta = (ToolTip = "Whether to use custom dialogue style configuration instead of a preset style"))
	bool CustomDialogueStyle{false};

	/** Preset dialogue style when not using custom configuration (e.g., "Formal", "Casual", "Sarcastic") */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Dialogue Style",
		meta = (EditCondition = "!CustomDialogueStyle", EditConditionHides,
			ToolTip = "Preset dialogue style when not using custom configuration (e.g., 'Formal', 'Casual', 'Sarcastic')"))
	FString DialogueStyle;

	/** Adjectives describing the character's speaking style when using custom configuration */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Dialogue Style",
		meta = (EditCondition = "CustomDialogueStyle", EditConditionHides,
			ToolTip = "Adjectives describing the character's speaking style when using custom configuration"))
	FString Adjectives;

	/** Colloquialisms, slang, or regional speech patterns when using custom configuration */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Dialogue Style",
		meta = (EditCondition = "CustomDialogueStyle", EditConditionHides,
			ToolTip = "Colloquialisms, slang, or regional speech patterns when using custom configuration"))
	FString Colloquialism;

	/** Example dialogue lines that demonstrate the character's typical speech patterns and voice */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Dialogue Style",
		Meta = (ToolTip = "Example dialogue lines that demonstrate the character's typical speech patterns and voice"))
	FString ExampleDialogue;

	/** Core personality traits that define how the character thinks and behaves */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Character|Personality",
		Meta = (ToolTip = "Core personality traits that define how the character thinks and behaves"))
	FString PersonalityTraits;
};

/**
 * @enum EInworldRelationLabel
 * @brief Enumeration of relationship types between characters.
 *
 * This enum represents the categorized relationship status computed from
 * individual relationship values (trust, respect, familiarity, etc.).
 */
UENUM(BlueprintType)
enum class EInworldRelationLabel : uint8
{
	/** No significant relationship; neutral standing */
	NEUTRAL UMETA(DisplayName = "Neutral"),
	/** Basic social connection; know each other but not close */
	ACQUAINTANCE UMETA(DisplayName = "Acquaintance"),
	/** Positive friendly relationship with moderate trust and familiarity */
	FRIEND UMETA(DisplayName = "Friend"),
	/** Strong platonic bond with high trust, respect, and familiarity */
	CLOSE_FRIEND UMETA(DisplayName = "Close Friend"),
	/** Romantic interest with flirtation and some attraction */
	DATE UMETA(DisplayName = "Date"),
	/** Established romantic relationship with mutual attraction */
	RELATIONSHIP UMETA(DisplayName = "Relationship"),
	/** Deep committed romantic partnership with maximum trust and attraction */
	LIFE_PARTNER UMETA(DisplayName = "Life Partner"),
	/** Antagonistic relationship with negative trust and respect */
	ENEMY UMETA(DisplayName = "Enemy"),
	/** Intense hatred with extremely negative values across all metrics */
	ARCHENEMY UMETA(DisplayName = "Archenemy"),
};

/**
 * @struct FInworldRelation
 * @brief Multi-dimensional relationship metrics between two characters.
 *
 * This structure tracks five independent relationship values that combine to determine
 * the overall relationship type. Values typically range from -100 to 100, with thresholds
 * defining different relationship labels.
 */
USTRUCT(BlueprintType, meta = (HasNativeBreak = "/Script/InworldCharacter.InworldCharacterBFL:BreakInworldRelation"))
struct INWORLDCHARACTER_API FInworldRelation
{
	GENERATED_BODY()

	/** Level of trust between characters (-100 to 100); affects reliability and confidence */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Relation",
		Meta = (ToolTip = "Level of trust between characters (-100 to 100); affects reliability and confidence"))
	int32 Trust{0};

	/** Level of respect between characters (-100 to 100); affects how seriously they take each other */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Relation",
		Meta = (ToolTip = "Level of respect between characters (-100 to 100); affects how seriously they take each other"))
	int32 Respect{0};

	/** Level of familiarity between characters (0 to 100); how well they know each other */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Relation",
		Meta = (ToolTip = "Level of familiarity between characters (0 to 100); how well they know each other"))
	int32 Familiar{0};

	/** Level of romantic or flirtatious behavior (0 to 100); indicates romantic interest */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Relation",
		Meta = (ToolTip = "Level of romantic or flirtatious behavior (0 to 100); indicates romantic interest"))
	int32 Flirtatious{0};

	/** Level of physical or emotional attraction (-100 to 100); affects romantic potential */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Relation",
		Meta = (ToolTip = "Level of physical or emotional attraction (-100 to 100); affects romantic potential"))
	int32 Attraction{0};

	/**
	 * @brief Converts the relation values to a formatted string for display/debugging.
	 * @return String representation of all relationship values
	 */
	FString ToString() const
	{
		return FString::Printf(TEXT("Trust: %d, Respect: %d, Familiar: %d, Flirtatious: %d, Attraction: %d"), Trust, Respect,
			Familiar, Flirtatious, Attraction);
	}

	/**
	 * @brief Computes the relationship label based on current metric values.
	 *
	 * This function evaluates all five relationship metrics against predefined thresholds
	 * to determine the appropriate relationship category. The thresholds define specific
	 * combinations that result in different relationship types (friend, enemy, romantic, etc.).
	 *
	 * @return The relationship label enum value that best matches the current metrics
	 */
	EInworldRelationLabel GetLabel() const
	{
		if (Trust >= 20 && Respect >= 10 && Familiar >= 20 && Flirtatious >= 20 && Attraction >= 20)
		{
			return EInworldRelationLabel::LIFE_PARTNER;
		}
		if (Trust >= 10 && Respect >= 5 && Familiar >= 10 && Flirtatious >= 20 && Attraction >= 10)
		{
			return EInworldRelationLabel::RELATIONSHIP;
		}
		if (Trust >= 20 && Respect >= 20 && Familiar >= 20 && Flirtatious <= 5 && Attraction >= 20)
		{
			return EInworldRelationLabel::CLOSE_FRIEND;
		}
		if (Trust >= 10 && Respect >= 5 && Familiar >= 10 && Flirtatious <= 5 && Attraction >= 5)
		{
			return EInworldRelationLabel::FRIEND;
		}
		if (Trust >= 5 && Respect >= 0 && Familiar >= 5 && Flirtatious >= 5 && Attraction >= 5)
		{
			return EInworldRelationLabel::DATE;
		}
		if (Trust >= 5 && Respect >= 0 && Flirtatious <= 5 && Attraction >= 0)
		{
			return EInworldRelationLabel::ACQUAINTANCE;
		}
		if (Trust <= 0 && Respect <= -5 && Flirtatious <= 5 && Attraction <= -5)
		{
			return EInworldRelationLabel::ENEMY;
		}
		if (Trust <= 0 && Respect <= -20 && Flirtatious <= 5 && Attraction <= -20)
		{
			return EInworldRelationLabel::ARCHENEMY;
		}

		return EInworldRelationLabel::NEUTRAL;
	}

	/**
	 * @brief Converts the computed relationship label to a human-readable string.
	 *
	 * This function returns the string representation of the relationship label,
	 * useful for UI display and debugging purposes.
	 *
	 * @return Human-readable string describing the relationship type
	 */
	FString GetLabelString() const
	{
		switch (GetLabel())
		{
			case EInworldRelationLabel::ACQUAINTANCE:
				return "Acquaintance";
			case EInworldRelationLabel::FRIEND:
				return "Friend";
			case EInworldRelationLabel::CLOSE_FRIEND:
				return "Close Friend";
			case EInworldRelationLabel::DATE:
				return "Date";
			case EInworldRelationLabel::RELATIONSHIP:
				return "Relationship";
			case EInworldRelationLabel::LIFE_PARTNER:
				return "Life Partner";
			case EInworldRelationLabel::ENEMY:
				return "Enemy";
			case EInworldRelationLabel::ARCHENEMY:
				return "Archenemy";
			default:
				return "Neutral";
		}
	}
};

/**
 * @enum EInworldEmotionLabel
 * @brief Enumeration of emotional states for character expression.
 *
 * This enum represents the range of emotions that characters can express,
 * from negative states (contempt, anger) to positive states (joy, affection).
 * These emotions influence dialogue tone and character behavior.
 */
UENUM(BlueprintType)
enum class EInworldEmotionLabel : uint8
{
	/** Balanced emotional state with no strong feelings */
	NEUTRAL UMETA(DisplayName = "Neutral"),
	/** Scornful disrespect or disdain */
	CONTEMPT UMETA(DisplayName = "Contempt"),
	/** Hostile and aggressive attitude */
	BELLIGERENCE UMETA(DisplayName = "Belligerence"),
	/** Controlling and overbearing manner */
	DOMINEERING UMETA(DisplayName = "Domineering"),
	/** Disapproving and fault-finding expression */
	CRITICISM UMETA(DisplayName = "Criticism"),
	/** Strong displeasure and hostility */
	ANGER UMETA(DisplayName = "Anger"),
	/** State of mental or emotional strain */
	TENSION UMETA(DisplayName = "Tension"),
	/** Humor used to mask or cope with stress */
	TENSE_HUMOR UMETA(DisplayName = "Tense Humor"),
	/** Protective or justifying behavior against criticism */
	DEFENSIVENESS UMETA(DisplayName = "Defensiveness"),
	/** Complaining in an annoying or childish manner */
	WHINING UMETA(DisplayName = "Whining"),
	/** State of grief or unhappiness */
	SADNESS UMETA(DisplayName = "Sadness"),
	/** Emotional withdrawal or refusal to communicate */
	STONEWALLING UMETA(DisplayName = "Stonewalling"),
	/** Curious engagement and attention */
	INTEREST UMETA(DisplayName = "Interest"),
	/** Recognition and acceptance of others' feelings */
	VALIDATION UMETA(DisplayName = "Validation"),
	/** Amusement and lighthearted mood */
	HUMOR UMETA(DisplayName = "Humor"),
	/** Fond, caring, and loving feelings */
	AFFECTION UMETA(DisplayName = "Affection"),
	/** Unexpected reaction to new information */
	SURPRISE UMETA(DisplayName = "Surprise"),
	/** Intense happiness and delight */
	JOY UMETA(DisplayName = "Joy"),
	/** Strong aversion or revulsion */
	DISGUST UMETA(DisplayName = "Disgust")
};

/**
 * @struct FInworldEmotion
 * @brief Structure representing a character's current emotional state.
 *
 * This structure tracks the character's emotion which affects their dialogue
 * tone, behavior, and interaction style with other characters and the player.
 */
USTRUCT(BlueprintType, meta = (HasNativeBreak = "/Script/InworldCharacter.InworldCharacterBFL:BreakInworldEmotion"))
struct INWORLDCHARACTER_API FInworldEmotion
{
	GENERATED_BODY()

	/** The current emotional state of the character */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|Relation",
		Meta = (ToolTip = "The current emotional state of the character"))
	EInworldEmotionLabel Label{EInworldEmotionLabel::NEUTRAL};

	/**
	 * @brief Converts the emotion label to a human-readable string.
	 * @return String representation of the current emotion
	 */
	FString GetLabelString() const
	{
		switch (Label)
		{
			case EInworldEmotionLabel::NEUTRAL:
				return TEXT("Neutral");
			case EInworldEmotionLabel::CONTEMPT:
				return TEXT("Contempt");
			case EInworldEmotionLabel::BELLIGERENCE:
				return TEXT("Belligerence");
			case EInworldEmotionLabel::DOMINEERING:
				return TEXT("Domineering");
			case EInworldEmotionLabel::CRITICISM:
				return TEXT("Criticism");
			case EInworldEmotionLabel::ANGER:
				return TEXT("Anger");
			case EInworldEmotionLabel::TENSION:
				return TEXT("Tension");
			case EInworldEmotionLabel::TENSE_HUMOR:
				return TEXT("Tense Humor");
			case EInworldEmotionLabel::DEFENSIVENESS:
				return TEXT("Defensiveness");
			case EInworldEmotionLabel::WHINING:
				return TEXT("Whining");
			case EInworldEmotionLabel::SADNESS:
				return TEXT("Sadness");
			case EInworldEmotionLabel::STONEWALLING:
				return TEXT("Stonewalling");
			case EInworldEmotionLabel::INTEREST:
				return TEXT("Interest");
			case EInworldEmotionLabel::VALIDATION:
				return TEXT("Validation");
			case EInworldEmotionLabel::HUMOR:
				return TEXT("Humor");
			case EInworldEmotionLabel::AFFECTION:
				return TEXT("Affection");
			case EInworldEmotionLabel::SURPRISE:
				return TEXT("Surprise");
			case EInworldEmotionLabel::JOY:
				return TEXT("Joy");
			case EInworldEmotionLabel::DISGUST:
				return TEXT("Disgust");
			default:
				return TEXT("Unknown");
		}
	}
};

/**
 * @enum EInworldGoalResponseType
 * @brief Enumeration of response types when a character goal is activated.
 */
UENUM(BlueprintType)
enum class EInworldGoalResponseType : uint8
{
	/** No special response; character responds naturally */
	NONE UMETA(DisplayName = "None"),
	/** Character follows an instruction prompt when goal activates */
	INSTRUCTION UMETA(DisplayName = "Instruction"),
	/** Character speaks a predefined verbatim line when goal activates */
	VERBATIM UMETA(DisplayName = "Verbatim")
};

/**
 * @enum EInworldKnowledgeFilter
 * @brief Enumeration of knowledge filtering levels for character responses.
 *
 * These filters control what information characters can access and discuss,
 * useful for enforcing character expertise boundaries and time period accuracy.
 */
UENUM(BlueprintType)
enum class EInworldKnowledgeFilter : uint8
{
	/** No filtering; character can discuss any topics */
	NONE UMETA(DisplayName = "None"),
	/** Moderate filtering; limits knowledge to specified expertise areas and time period */
	MILD_FILTER UMETA(DisplayName = "Mild"),
	/** Strict filtering; only explicitly specified knowledge allowed */
	STRICT_FILTER UMETA(DisplayName = "Strict")
};

/**
 * @struct FInworldKnowledgeFilter
 * @brief Configuration for character knowledge filtering.
 *
 * This structure wraps the knowledge filter setting for character configuration.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldKnowledgeFilter
{
	GENERATED_BODY()

	/** The knowledge filtering level to apply to this character */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Knowledge",
		Meta = (ToolTip = "The knowledge filtering level to apply to this character"))
	EInworldKnowledgeFilter KnowledgeFilter{EInworldKnowledgeFilter::NONE};
};

/**
 * @struct FInworldGoal
 * @brief DataTable row structure for defining character goals and their activation conditions.
 *
 * Goals represent specific objectives or responses that characters can achieve or perform
 * when certain conditions (intents) are met during conversation. They allow for scripted
 * or guided character behavior while maintaining natural dialogue flow.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldGoal : public FTableRowBase
{
	GENERATED_BODY()

	/** The type of response the character gives when this goal is activated */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Goals",
		Meta = (ToolTip = "The type of response initiated by the goal's activation."))
	EInworldGoalResponseType ResponseType{EInworldGoalResponseType::NONE};

	/** Instruction prompt for the AI when the goal activates (used with INSTRUCTION response type) */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Goals",
		Meta = (EditCondition = "ResponseType == EInworldGoalResponseType::INSTRUCTION", EditConditionHides,
			ToolTip = "Instruction for the prompt when the goal is activated."))
	FString Instruction;

	/** Exact text the character speaks when the goal activates (used with VERBATIM response type) */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Goals",
		Meta = (EditCondition = "ResponseType == EInworldGoalResponseType::VERBATIM", EditConditionHides,
			ToolTip = "Agent verbatim response when the goal is activated."))
	FString Verbatim;

	/** Whether this goal can be activated multiple times or only once per conversation */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Goals", Meta = (ToolTip = "Whether the goal can be repeated."))
	bool bRepeatable{false};

	/** List of intent identifiers that trigger this goal's activation */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Goals",
		Meta = (ToolTip = "List of intent identifiers that can trigger goal activation."))
	TArray<FName> Intents{};
};

/**
 * @struct FInworldConversationCharacter
 * @brief Simplified representation of a character participating in a conversation.
 *
 * This structure provides basic identification information for characters
 * involved in a conversation for tracking and UI purposes.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldConversationCharacter
{
	GENERATED_BODY()

	/** Unique identifier for the character */
	UPROPERTY(
		VisibleAnywhere, BlueprintReadOnly, Category = "Conversation", Meta = (ToolTip = "Unique identifier for the character"))
	FString Id{};

	/** Display name of the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation", Meta = (ToolTip = "Display name of the character"))
	FString Name{};
};

/**
 * @struct FInworldConversationState
 * @brief Current state information for an active conversation.
 *
 * This structure tracks the participants, speaking order, and type of an ongoing
 * conversation, used for managing multi-character dialogue and conversation flow.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldConversationState
{
	GENERATED_BODY()

	/** List of all characters currently participating in the conversation */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "List of all characters currently participating in the conversation"))
	TArray<FInworldConversationCharacter> Participants{};

	/** Name of the character who spoke most recently */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Name of the character who spoke most recently"))
	FString LastSpeakerName;

	/** Whether the player is actively participating in this conversation */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Whether the player is actively participating in this conversation"))
	bool IsPlayerInConversation{false};

	/** Whether this is a group conversation (3+ participants) or two-person dialogue */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Whether this is a group conversation (3+ participants) or two-person dialogue"))
	bool IsGroup{false};
};

/**
 * @struct FInworldCharacterResponse
 * @brief Structure representing a character's response to a query or interaction.
 *
 * This structure captures the input query, the generated response, and safety
 * information for a single character interaction exchange.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldCharacterResponse
{
	GENERATED_BODY()

	/** Unique identifier for this message exchange */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Unique identifier for this message exchange"))
	FString MessageId;

	/** The input query or prompt that prompted this response */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "The input query or prompt that prompted this response"))
	FString Query;

	/** The generated response text from the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "The generated response text from the character"))
	FString Result;

	/** Whether this response was flagged as potentially unsafe by content filters */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Whether this response was flagged as potentially unsafe by content filters"))
	bool UnSafe{false};

	/**
	 * @brief Resets all fields to their default values.
	 */
	void Reset()
	{
		MessageId = "";
		Query = "";
		Result = "";
		UnSafe = false;
	}
};

/**
 * @struct FInworldMessage
 * @brief Base structure for messages exchanged during character interactions.
 *
 * This polymorphic structure serves as the base for different message types,
 * containing common fields like message ID, data payload, timestamps, and runtime data.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldMessage
{
	GENERATED_BODY()
	virtual ~FInworldMessage() = default;

	/** Unique identifier for this message */
	UPROPERTY(
		VisibleAnywhere, BlueprintReadOnly, Category = "Conversation", Meta = (ToolTip = "Unique identifier for this message"))
	FString MessageId;

	/** Handle to the message data payload from the graph system */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Handle to the message data payload from the graph system"))
	FInworldDataHandle DataHandle;

	/** Timestamp when the message was sent */
	UPROPERTY(
		VisibleAnywhere, BlueprintReadOnly, Category = "Conversation", Meta = (ToolTip = "Timestamp when the message was sent"))
	FDateTime TimeSent;

	/** Additional runtime data attached to this message (e.g., player profile, context) */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Additional runtime data attached to this message (e.g., player profile, context)"))
	TMap<FName, FInworldDataHandle> RuntimeData;

	/**
	 * @brief Retrieves runtime data by key.
	 * @param Key The name key to look up in the runtime data map
	 * @return Pointer to the runtime data handle, or nullptr if not found
	 */
	const FInworldDataHandle* GetRuntimeData(FName Key) const
	{
		return RuntimeData.Find(Key);
	}

	/**
	 * @brief Attempts to retrieve player profile data from runtime data.
	 *
	 * This helper function looks up runtime data by key and attempts to extract
	 * a player profile structure from it.
	 *
	 * @param Key The runtime data key to search for
	 * @param OutPlayerProfile Output parameter for the retrieved player profile
	 * @return True if a valid player profile was found and extracted
	 */
	bool GetPlayerProfileRuntimeData(FName Key, FInworldPlayerProfile& OutPlayerProfile) const
	{
		if (const FInworldDataHandle* PlayerProfileDataHandle = RuntimeData.Find(Key); PlayerProfileDataHandle != nullptr)
		{
			if (const FInworldData_Struct* Struct = PlayerProfileDataHandle->Unwrap<FInworldData_Struct>(); Struct != nullptr)
			{
				if (Struct->GetData(OutPlayerProfile))
				{
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @brief Checks if the message contains valid data.
	 * @return True if the message has a valid data handle
	 */
	virtual bool IsValid() const
	{
		return DataHandle.Data.IsValid();
	}

	/**
	 * @brief Resets all message fields to their default values.
	 */
	virtual void Reset()
	{
		MessageId = "";
		DataHandle = {};
		TimeSent = FDateTime::MinValue();
		RuntimeData = {};
	}
};

/**
 * @struct FInworldCharacterMessage
 * @brief Message structure specific to individual character interactions.
 *
 * This derived message type includes the graph execution ID for tracking
 * the specific graph instance that generated the character's response.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldCharacterMessage : public FInworldMessage
{
	GENERATED_BODY()

	/** Unique identifier for the graph execution that generated this message */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Unique identifier for the graph execution that generated this message"))
	FString ExecutionId;

	/**
	 * @brief Resets all message fields including execution ID.
	 */
	virtual void Reset() override
	{
		FInworldMessage::Reset();
		ExecutionId = "";
	}
};

/**
 * @struct FInworldConversationMessage
 * @brief Message structure for multi-character conversations.
 *
 * This derived message type includes responder information for tracking
 * which character is responding to whom in group conversations.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldConversationMessage : public FInworldMessage
{
	GENERATED_BODY()

	/** Unique identifier of the character responding to this message */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Unique identifier of the character responding to this message"))
	FString ResponderId;

	/** Message ID of the responder's message in the conversation chain */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Conversation",
		Meta = (ToolTip = "Message ID of the responder's message in the conversation chain"))
	FString ResponderMessageId;

	/**
	 * @brief Resets all message fields including responder information.
	 */
	virtual void Reset() override
	{
		FInworldMessage::Reset();
		ResponderId = "";
		ResponderMessageId = "";
	}
};

/**
 * @enum EInworldComponentType
 * @brief Enumeration of character component implementation types.
 */
UENUM(BlueprintType)
enum class EInworldComponentType : uint8
{
	/** Simplified character component with basic functionality */
	Simple UMETA(DisplayName = "InworldSimpleCharacterComponent"),

	/** Full-featured character component with advanced capabilities */
	Full UMETA(DisplayName = "InworldCharacterComponent")
};

/**
 * @struct FInworldCharacterConfig
 * @brief Complete configuration structure for defining Inworld character behavior and properties.
 *
 * This DataTable row structure contains all configuration options for creating an Inworld
 * character, including profile information, voice settings, initial emotional state,
 * relationships, knowledge, goals, and intents. It supports both simple and full character
 * component types with appropriate configuration sections for each.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FInworldCharacterConfig : public FTableRowBase
{
	GENERATED_BODY()

	/** Type of character component to use (Simple or Full) */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Metadata",
		Meta = (ToolTip = "Type of character component to use (Simple or Full)"))
	EInworldComponentType ComponentType = EInworldComponentType::Full;

	/** Character profile defining personality, background, and dialogue style */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Simple Character Config",
		Meta = (ToolTip = "Character profile defining personality, background, and dialogue style"))
	FInworldCharacterProfile CharacterProperties;

	/** Voice configuration for text-to-speech synthesis */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Simple Character Config",
		Meta = (ToolTip = "Voice configuration for text-to-speech synthesis"))
	FInworldVoice VoiceProperties;

	/** DataTable containing initial conversation history entries for context */
	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Simple Character Config",
		Meta = (RequiredAssetDataTags = "RowStructure=/Script/InworldRuntime.InworldEventHistoryEntry",
			ToolTip = "DataTable containing initial conversation history entries for context"))
	class UDataTable* InitialHistoryTable{nullptr};

	/** Starting emotional state for the character at conversation begin */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Full Character Config",
		Meta = (ToolTip = "Starting emotional state for the character at conversation begin",
			EditCondition = "ComponentType == EInworldComponentType::Full", EditConditionHides))
	EInworldEmotionLabel InitialEmotion{EInworldEmotionLabel::NEUTRAL};

	/** Initial relationship metrics with the player or other characters */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Full Character Config",
		Meta = (ToolTip = "Initial relationship metrics with the player or other characters",
			EditCondition = "ComponentType == EInworldComponentType::Full", EditConditionHides))
	FInworldRelation InitialRelation;

	/** Knowledge base assets available to the character for responses */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Full Character Config",
		Meta = (ToolTip = "Knowledge base assets available to the character for responses",
			EditCondition = "ComponentType == EInworldComponentType::Full", EditConditionHides))
	TMap<FName, UInworldTextEmbeddingAsset*> InitialKnowledge;

	/** Knowledge filtering settings to limit character's topic scope */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Full Character Config",
		Meta = (ToolTip = "Knowledge filtering settings to limit character's topic scope",
			EditCondition = "ComponentType == EInworldComponentType::Full", EditConditionHides))
	FInworldKnowledgeFilter KnowledgeFilter;

	/** DataTable defining character goals and their activation conditions */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Full Character Config",
		Meta = (RequiredAssetDataTags = "RowStructure=/Script/InworldCharacter.InworldGoal",
			ToolTip = "DataTable defining character goals and their activation conditions",
			EditCondition = "ComponentType == EInworldComponentType::Full", EditConditionHides))
	UDataTable* GoalTable{nullptr};

	/** Intent recognition assets for identifying player intentions */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Full Character Config",
		Meta = (ToolTip = "Intent recognition assets for identifying player intentions",
			EditCondition = "ComponentType == EInworldComponentType::Full", EditConditionHides))
	TMap<FName, UInworldTextEmbeddingAsset*> InitialIntents;
};

/**
 * @struct FSpeakerRule
 * @brief Defines a single, deterministic speaker sequence for a conversation.
 * This is used by the USpeakerRuleDirector to manage turn-based or scripted dialogue.
 */
USTRUCT(BlueprintType)
struct INWORLDCHARACTER_API FSpeakerRule
{
	GENERATED_BODY()

	/** @brief The unique identifier for this rule */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speaker Rule")
	FName RuleID;

	/** @brief An ordered list of CharacterIDs. The conversation will follow this sequence. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speaker Rule")
	TArray<FString> SpeakerSequence;

	/** @brief If true, the sequence will loop back to the beginning after the last speaker. If false, the rule will deactivate
	 * after finishing. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speaker Rule",
		meta = (ToolTip =
					"If true, the sequence will loop back to the beginning. If false, the rule will deactivate after finishing."))
	bool bLoop = false;
};
