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

#include "Components/ActorComponent.h"
#include "CoreMinimal.h"
#include "Graph/Assets/InworldGraphAsset.h"
#include "Graph/InworldGraph.h"

#include "InworldGraphComponent.generated.h"

class UInworldGraphComponent;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInworldGraphCompiled, UInworldGraphComponent*, GraphComponent, bool, bSuccess);
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnInworldGraphCompiledNative, UInworldGraphComponent* /*GraphComponent*/, bool /*bSuccess*/);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnInworldGraphResult, UInworldGraphComponent*, GraphComponent, const FString&,
	ExecutionId, const FString&, NodeId, const FInworldDataHandle&, Data);
DECLARE_MULTICAST_DELEGATE_FourParams(FOnInworldGraphResultNative, UInworldGraphComponent* /*GraphComponent*/,
	const FString& /*ExecutionId*/, const FString& /*NodeId*/, const FInworldDataHandle& /*Data)*/);

DECLARE_MULTICAST_DELEGATE_OneParam(FInworldGraphComponentBeginPlay, UInworldGraphComponent* /*GraphComponent*/);
DECLARE_MULTICAST_DELEGATE_OneParam(FInworldGraphComponentEndPlay, UInworldGraphComponent* /*GraphComponent*/);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnInworldGraphExecutionStatus, UInworldGraphComponent*, GraphComponent,
	const FString&, ExecutionId, EInworldGraphExecutionStatus, Status);
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnInworldGraphExecutionStatusNative, UInworldGraphComponent* /*GraphComponent*/,
	const FString& /*ExecutionId*/, EInworldGraphExecutionStatus /*Status*/);

/**
 * @class UInworldGraphComponent
 * @brief Actor component for managing Inworld graphs within the game world.
 *
 * This abstract component provides the foundation for integrating Inworld graph
 * functionality into actors. It manages graph creation, compilation, and execution
 * while providing delegates for monitoring graph events and results.
 */
UCLASS(ClassGroup = (Inworld), Abstract, BlueprintType, Blueprintable)
class INWORLDRUNTIME_API UInworldGraphComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintAssignable)
	FOnInworldGraphCompiled OnInworldGraphCompiled;
	FOnInworldGraphCompiledNative OnInworldGraphCompiledNative;

	UPROPERTY(BlueprintAssignable)
	FOnInworldGraphResult OnInworldGraphResult;
	FOnInworldGraphResultNative OnInworldGraphResultNative;

	UPROPERTY(BlueprintAssignable, Category = "Inworld")
	FOnInworldGraphExecutionStatus OnInworldGraphExecutionStatus;
	FOnInworldGraphExecutionStatusNative OnInworldGraphExecutionStatusNative;

	static FInworldGraphComponentBeginPlay OnInworldGraphComponentBeginPlay;
	static FInworldGraphComponentEndPlay OnInworldGraphComponentEndPlay;

	UInworldGraphComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

	virtual void BeginPlay() override;
	virtual void EndPlay(EEndPlayReason::Type Reason) override;

	/**
	 * @brief Creates the graph from the associated GraphAsset.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld")
	void CreateGraph();

	/**
	 * @brief Executes the graph with the provided input data and runtime data.
	 * @param InputData The input data to pass to the graph.
	 * @param RuntimeData Runtime data map accessible by nodes during execution.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld", meta = (AutoCreateRefTerm = "RuntimeData"))
	UPARAM(meta = (DisplayName = "Execution Id"))
	FString ExecuteGraph(const FInworldDataHandle& InputData, const TMap<FName, FInworldDataHandle>& RuntimeData);

protected:
	UFUNCTION(BlueprintNativeEvent, Category = "Inworld")
	void OnGraphResult(const FString& ExecutionId, const FString& NodeId, const FInworldDataHandle& DataHandle);
	virtual void OnGraphResult_Implementation(
		const FString& ExecutionId, const FString& NodeId, const FInworldDataHandle& DataHandle);

	virtual void OnGraphCompiled(UInworldGraph* CompiledGraph, bool bSuccess);

protected:
	UPROPERTY(EditDefaultsOnly, Category = "Graph",
		Meta = (ToolTip = "Whether to automatically create and compile the graph on BeginPlay"))
	bool bCreateGraphOnBeginPlay = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Graph", Meta = (ToolTip = "The graph asset to instantiate and execute"))
	TObjectPtr<UInworldGraphAsset> GraphAsset;

	UPROPERTY()
	TObjectPtr<UInworldGraph> Graph;
};
