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

#pragma once
#include "Components/ActorComponent.h"
#include "Conversation/InworldConversationTarget.h"

#include "InworldConversationTargetComponent.generated.h"

/** Native delegate fired when conversation target component is initialized */
DECLARE_MULTICAST_DELEGATE_OneParam(
	FInworldConversationTargetInitialized, UInworldConversationTargetComponent* /*ConversationTarget*/);

/** Native delegate fired when conversation target component begins play */
DECLARE_MULTICAST_DELEGATE_OneParam(
	FInworldConversationTargetBeginPlay, UInworldConversationTargetComponent* /*ConversationTarget*/);

/** Native delegate fired when conversation target component ends play */
DECLARE_MULTICAST_DELEGATE_OneParam(FInworldConversationTargetEndPlay, UInworldConversationTargetComponent* /*ConversationTarget*/);

/** Delegate fired when the conversation target component is ready and initialized */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(
	FOnInworldConversationTargetReady, UInworldConversationTargetComponent*, ConversationTarget);

/** Native delegate fired when conversation target component is ready and initialized */
DECLARE_MULTICAST_DELEGATE_OneParam(
	FOnInworldConversationTargetReadyNative, UInworldConversationTargetComponent* /*ConversationTarget*/);

/**
 * @class UInworldConversationTargetComponent
 * @brief Abstract base component for conversation target implementations.
 *
 * This component provides the foundation for any actor component that can serve as
 * a conversation target in the Inworld system. It implements the IInworldConversationTarget
 * interface and provides common functionality for readiness management, message handling,
 * and lifecycle events.
 *
 * Key Features:
 * - Conversation target interface implementation
 * - Readiness state management
 * - Lifecycle event broadcasting
 * - Message handling abstraction
 * - Blueprint and C++ integration
 */
UCLASS(ClassGroup = (Inworld), Abstract, Blueprintable, BlueprintType)
class INWORLDCHARACTER_API UInworldConversationTargetComponent : public UActorComponent, public IInworldConversationTarget
{
	GENERATED_BODY()

public:
	/**
	 * @brief Constructor for the conversation target component.
	 * @param ObjectInitializer Unreal Engine object initialization parameters
	 */
	UInworldConversationTargetComponent(const FObjectInitializer& ObjectInitializer);

	/**
	 * @brief Retrieves the unique identifier for this conversation target.
	 * @return The conversation target's unique ID string
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld")
	const FString& GetId() const
	{
		return Id;
	}

	/**
	 * Checks if the conversation target is ready and initialized.
	 * @return True if the target is ready, false otherwise
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld")
	bool IsReady()
	{
		return bIsReady;
	}

protected:
	/** Called when the component begins play */
	virtual void BeginPlay() override;

	/** Initializes the component */
	virtual void InitializeComponent() override;

	/** Called when the component ends play */
	virtual void EndPlay(EEndPlayReason::Type Reason) override;

	/**
	 * Attempts to signal that the character component is ready and initialized.
	 * If the component is already marked as ready, this method exits without further action.
	 * When readiness is achieved, it triggers the OnCharacterReady and OnCharacterReadyNative events.
	 */
	virtual void TrySignalReady();

	/**
	 * Cancels the current message, clears the message queue, and stops the character's speech.
	 */
	virtual void Interrupt_Implementation() override
		PURE_VIRTUAL(UInworldConversationTargetComponent::Interrupt_Implementation, return;);

	/**
	 * Sends a message to this conversation target.
	 *
	 * The message contains data that should be processed by the
	 * conversation target's AI system to generate appropriate text or speech responses.
	 *
	 * @param Message A data handle holding the message
	 * @return An FString identifier for the sent message
	 */
	virtual FString SendMessage_Implementation(const FInworldDataHandle& Message) override
		PURE_VIRTUAL(UInworldConversationTargetComponent::SendMessage_Implementation, return "";);

	/**
	 * Sends a message to this conversation target with player information.
	 *
	 * The message contains data that should be processed by the
	 * conversation target's AI system to generate appropriate text or speech responses.
	 *
	 * @param Message A data handle holding the message
	 * @param PlayerProfile Runtime data that holds information about the player that sent the message
	 * @return An FString identifier for the sent message
	 */
	FString SendPlayerMessage_Implementation(const FInworldDataHandle& Message, const FInworldPlayerProfile& PlayerProfile)
		PURE_VIRTUAL(UInworldConversationTargetComponent::SendPlayerMessage_Implementation, return "";);

	/**
	 * Sends a message to this conversation target with runtime data.
	 *
	 * The message contains data that should be processed by the
	 * conversation target's AI system to generate appropriate text or speech responses.
	 *
	 * @param Message A data handle holding the message
	 * @param RuntimeData The runtime data
	 * @return An FString identifier for the sent message
	 */
	virtual FString SendDataMessage_Implementation(
		const FInworldDataHandle& Message, const TMap<FName, FInworldDataHandle>& RuntimeData) override
		PURE_VIRTUAL(UInworldConversationTargetComponent::SendDataMessage_Implementation, return "";);

public:
	/** Static delegate broadcast when any conversation target component is initialized */
	static FInworldConversationTargetInitialized OnInworldConversationTargetInitialized;

	/** Static delegate broadcast when any conversation target component begins play */
	static FInworldConversationTargetBeginPlay OnInworldConversationTargetBeginPlay;

	/** Static delegate broadcast when any conversation target component ends play */
	static FInworldConversationTargetEndPlay OnInworldConversationTargetEndPlay;

	/** Event fired when conversation target component is ready and initialized */
	UPROPERTY(BlueprintAssignable, Category = "Inworld")
	FOnInworldConversationTargetReady OnConversationTargetReady;
	FOnInworldConversationTargetReadyNative OnConversationTargetReadyNative;

	/** Event fired when a character response is generated */
	UPROPERTY(BlueprintAssignable, Category = "Inworld")
	FOnInworldConversationCharacterMessage OnCharacterMessage;
	FOnInworldConversationCharacterMessageNative OnCharacterMessageNative;

	/** Event fired when a player message is received */
	UPROPERTY(BlueprintAssignable, Category = "Inworld")
	FOnInworldConversationPlayerMessage OnPlayerMessage;
	FOnInworldConversationPlayerMessageNative OnPlayerMessageNative;

protected:
	/** Unique identifier for this conversation target */
	UPROPERTY(
		EditAnywhere, BlueprintReadOnly, Category = "Inworld", Meta = (ToolTip = "Unique identifier for this conversation target"))
	FString Id;

	/** Whether the conversation target is ready and initialized */
	UPROPERTY(
		BlueprintReadOnly, Category = "Inworld", Meta = (ToolTip = "Whether the conversation target is ready and initialized"))
	bool bIsReady;
};
