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

#pragma once

#include "Containers/Queue.h"
#include "CoreMinimal.h"
#include "Graph/InworldGraphRuntimeData.h"
#include "InworldRuntimeTypes.h"

#include "InworldGraphRuntimeData_EventHistory.generated.h"

namespace inworld
{
class vector_Event;
}

/**
 * @class UInworldGraphRuntimeData_EventHistory
 * @brief Runtime data class for managing event history in Inworld graphs.
 *
 * This class creates and manages an event history system that tracks various types of events
 * (primarily speech events) during graph execution. It provides functionality for adding,
 * retrieving, and formatting event history with configurable capacity and formatting options.
 */
UCLASS(BlueprintType, meta = (DisplayName = "EventHistory Data"))
class INWORLDRUNTIME_API UInworldGraphRuntimeData_EventHistory : public UInworldGraphRuntimeData
{
	GENERATED_BODY()

public:
	/**
	 * @brief Default constructor for the event history runtime data.
	 */
	UInworldGraphRuntimeData_EventHistory();

	/**
	 * @brief Initializes the event history runtime data.
	 *
	 * This override implementation sets up the event history system, processes any
	 * initial history data from the configured data table, and prepares the system
	 * for tracking events during graph execution.
	 */
	virtual void Initialize_Implementation() override;

	/**
	 * @brief Retrieves the event history data wrapped in an InworldDataHandle.
	 *
	 * This override implementation returns the current event history data,
	 * making it accessible to nodes within the graph system.
	 *
	 * @return Handle containing the event history data
	 */
	virtual FInworldDataHandle GetData() override;

	/**
	 * @brief Sets the initial event history data table.
	 *
	 * This function configures the data table that contains initial event history entries
	 * to be loaded during initialization. The data table must use the InworldEventHistoryEntry
	 * row structure.
	 *
	 * @param InEventHistoryTable The data table containing initial event history entries
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	void Set(UDataTable* InEventHistoryTable)
	{
		InitialHistoryTable = InEventHistoryTable;
	}

	/**
	 * @brief Retrieves the speech event history as structured data.
	 *
	 * This function returns all recorded speech events wrapped in a structured
	 * format that can be easily processed by other graph nodes or systems.
	 *
	 * @return Structured event history data containing all speech events
	 */
	UFUNCTION(BlueprintPure, Category = "Inworld|Graph|EventHistory")
	FInworldHistoryEventData GetHistoryEventData() const
	{
		return FInworldHistoryEventData{GetSpeechEvents()};
	}

	/** Adds a generic event to the event history.
	 *
	 * This function stores the provided text event and appends it to the history.
	 * If the history reaches its capacity, the oldest event is removed.
	 *
	 * @param Event The text event to be added to the history.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	void AddGenericEvent(const FString& Event);

	/** Adds a speech event to the event history.
	 *
	 * This function records a speech event, storing the agent's name and utterance.
	 * The event is formatted based on the SpeechEventFormatter and appended to the history.
	 * If the history reaches its capacity, the oldest event is removed.
	 *
	 * @param Speech The speech event data containing the agent's name and utterance.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	void AddSpeechEvent(const FInworldEventSpeech& Speech);

	/** Clear the event history.
	 *
	 * This function removes all stored events and resets the history string.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	void Clear();

	/** Retrieves the full event  history as a formatted string.
	 *
	 * This function returns a concatenated string representation of all stored events.
	 *
	 * @return A reference to the history string containing all recorded events.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	const FString& GetHistoryString() const
	{
		return HistoryString;
	}

	/**
	 * @brief Retrieves the native event history interface.
	 *
	 * This function provides access to the underlying native event history object
	 * for advanced operations and integration with the internal Inworld system.
	 *
	 * @return Shared pointer to the native event history interface
	 */
	const TSharedPtr<inworld::vector_Event> GetEventHistory() const
	{
		return EventHistory;
	}

	/** Retrieves the speech event history.
	 *
	 * This function returns a representation of all stored speech events.
	 *
	 * @return A reference to the history containing all recorded speech events.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	const TArray<FInworldEventSpeech>& GetSpeechEvents() const
	{
		return SpeechEvents;
	}

	/**
	 * @brief Outputs debug information about the event history to the console.
	 *
	 * This function prints detailed information about the current event history state,
	 * including all stored events, for debugging and development purposes.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Graph|EventHistory")
	void DebugDumpEventHistory();

protected:
	/** Format string for speech events, supports {AgentName} and {Utterance} placeholders */
	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Event History Runtime Data",
		meta = (ToolTip = "Format string for speech events, supports {AgentName} and {Utterance} placeholders"))
	FString SpeechEventFormatter{"{AgentName}: {Utterance}"};

	/** Delimiter string used to separate events in the formatted history string */
	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Event History Runtime Data",
		meta = (ExposeOnSpawn = "true", ToolTip = "Delimiter string used to separate events in the formatted history string"))
	FString Delimiter{"\n"};

	/** Maximum number of events to store (INDEX_NONE for unlimited capacity) */
	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Event History Runtime Data",
		meta = (ExposeOnSpawn = "true", ToolTip = "Maximum number of events to store (INDEX_NONE for unlimited capacity)"))
	int32 Capacity{INDEX_NONE};

	/** Data table containing initial event history entries to load during initialization */
	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Event History Runtime Data",
		Meta = (ExposeOnSpawn = "true", RequiredAssetDataTags = "RowStructure=/Script/InworldRuntime.InworldEventHistoryEntry",
			ToolTip = "Data table containing initial event history entries to load during initialization"))
	class UDataTable* InitialHistoryTable{nullptr};

private:
	/**
	 * @brief Internal function to process and add events to the history.
	 */
	void AddEvent();

	/** Internal native event history interface */
	TSharedPtr<inworld::vector_Event> EventHistory{};

	// TODO: Support other event types
	/** Array storing all recorded speech events */
	TArray<FInworldEventSpeech> SpeechEvents{};

	/** Queue tracking the size of each entry for capacity management */
	TQueue<int32> EntrySizes{};

	/** Formatted string containing the complete event history */
	FString HistoryString{};
};
