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

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "InworldData.h"
#include "Misc/TVariant.h"
#include "Tasks/Task.h"
#include "UObject/UObjectThreadContext.h"

#include "InworldGraphRuntimeData.generated.h"

namespace inworld
{
namespace graph
{
struct CompileContext;
}
}	 // namespace inworld

/**
 * @class UInworldGraphRuntimeData
 * @brief Abstract base class for data the graph can access at runtime
 */
UCLASS(Abstract, BlueprintType, Blueprintable, EditInlineNew, DefaultToInstanced)
class INWORLDRUNTIME_API UInworldGraphRuntimeData : public UObject
{
	GENERATED_BODY()

public:
	virtual void PostInitProperties() override
	{
		Super::PostInitProperties();
		if (!HasAnyFlags(RF_WasLoaded) && !HasAnyFlags(RF_ClassDefaultObject) && !FUObjectThreadContext::Get().IsRoutingPostLoad)
		{
			Initialize();
		}
	}

	virtual void Serialize(FArchive& Ar) override
	{
		Super::Serialize(Ar);
		if (Ar.IsLoading() && !HasAnyFlags(RF_ClassDefaultObject))
		{
			Initialize();
		}
	}

	/**
	 * @brief Retrieves the key identifier for this runtime data.
	 * @return The name key used to identify this runtime data in the graph
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld Runtime Data")
	FName GetKey()
	{
		return Key;
	}

	/**
	 * @brief Retrieves the actual data wrapped in an InworldDataHandle.
	 *
	 * This pure virtual function must be implemented by derived classes to provide
	 * the specific data that this runtime data object manages.
	 *
	 * @return The data handle containing the runtime data
	 */
	UFUNCTION(BlueprintPure, Category = "Inworld Runtime Data")
	virtual FInworldDataHandle GetData() PURE_VIRTUAL(UInworldGraphRuntimeData::GetData, return {};);

	/**
	 * @brief Convenience function to get both the key and data as a pair.
	 * @return A tuple containing the key and data handle
	 */
	TTuple<FName, FInworldDataHandle> GetDataPair()
	{
		return {Key, GetData()};
	}

protected:
	/** The unique key identifier for this runtime data object */
	UPROPERTY(EditDefaultsOnly, Category = "Inworld", Meta = (ToolTip = "The unique key identifier for this runtime data object"))
	FName Key{};

	/**
	 * @brief Initializes the runtime data object.
	 *
	 * This function is called to initialize the runtime data. Override in derived classes
	 * to perform custom initialization logic. The base implementation simply marks the
	 * object as initialized.
	 */
	UFUNCTION(BlueprintNativeEvent, Category = "Inworld Runtime Data")
	void Initialize();
	virtual void Initialize_Implementation()
	{
	}
};
