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

#pragma once

#include "CoreMinimal.h"
#include "Graph/InworldData.h"
#include "Graph/InworldNode.h"
#include "Graph/InworldProcessContext.h"

#include "InworldNode_Custom.generated.h"

namespace inworld
{
class NodeWrapper;
FInworldDataHandle ExecuteCustomNode(
	UInworldNode_Custom* Node, UInworldProcessContext* ProcessContext, const TArray<FInworldDataHandle>& Inputs);
}	 // namespace inworld

/**
 * @class UInworldNode_Custom
 * @brief Base class for creating custom node behaviors in the InworldGraph.
 *
 * This abstract class allows developers to implement custom processing logic for graph nodes
 * through Blueprint or C++ implementations. Custom nodes can process input data and produce
 * output data based on custom logic, extending the graph system's capabilities.
 *
 * Key features:
 * - Blueprintable: Can be extended in Blueprints to create custom node types
 * - Configurable execution thread: Processing can occur in game thread or background thread
 *
 * To implement a custom node:
 * 1. Create a Blueprint or C++ class inheriting from UInworldNode_Custom
 * 2. Implement the Process function to define custom behavior
 */
UCLASS(Blueprintable, BlueprintType, Abstract)
class INWORLDRUNTIME_API UInworldNode_Custom : public UInworldNode
{
	GENERATED_BODY()

public:
	/**
	 * @brief Determines if the Process function should execute on the game thread.
	 *
	 * This function returns the current thread execution preference for the node's
	 * processing logic, allowing the runtime system to schedule execution appropriately.
	 *
	 * @return True if processing should occur on the game thread, false for background execution
	 */
	bool ShouldExecuteProcessInGameThread() const
	{
		return bExecuteProcessInGameThread;
	}

protected:
	/**
	 * @brief Generates JSON configuration for the custom node.
	 *
	 * This override generates the JSON configuration needed for the custom node's
	 * processing operations. The configuration includes node-specific settings and
	 * any required parameters for runtime execution.
	 *
	 * @param GraphJson The JSON object to populate with the node's configuration data
	 * @return Error code indicating success or failure of configuration generation
	 */
	virtual EInworldRuntimeErrors GetJsonConfig(const TSharedRef<FJsonObject>& GraphJson) override;

protected:
	/**
	 * @brief Controls whether the Process function executes on the game thread
	 *
	 * When true, ensures the Process function runs on the game thread, allowing safe access
	 * to UObject properties and other game thread-only operations. When false, the Process
	 * function may run on a background thread for better performance. Default is false.
	 * Set this to true if your custom node needs to access UObjects or perform operations
	 * that are only safe on the game thread.
	 */
	UPROPERTY(EditDefaultsOnly, Category = "Inworld",
		Meta = (ToolTip = "When true, ensures the Process function runs on the game thread for safe UObject access"))
	bool bExecuteProcessInGameThread{true};

private:
	/**
	 * @brief Process function will match Inputs to matching "Process" functions.
	 *
	 * This function will iterate over any UFUNCTION prefixed with "Process" to find
	 * a suitable match. Once found, the UFUNCTION will be called with the unwraped
	 * types. The return value will be wrapped in a DataHandle and returned to the graph.
	 *
	 * @param ProcessContext Runtime context containing graph execution state and runtime data
	 * @param Inputs Array of input data handles to be processed by the node
	 * @return Processed output data wrapped in an FInworldDataHandle
	 */
	FInworldDataHandle Process(const UInworldProcessContext* ProcessContext, const TArray<struct FInworldDataHandle>& Inputs) const;

	friend inworld::NodeWrapper;
	friend FInworldDataHandle inworld::ExecuteCustomNode(
		UInworldNode_Custom* Node, UInworldProcessContext* ProcessContext, const TArray<FInworldDataHandle>& Inputs);
};
