// Project Sword & Gun Copyright © 2021 Kevin Poretti

#pragma once

#include "CoreMinimal.h"

#include "SwordNGun/SNGTypes.h"


#include "SNGState.generated.h"

DECLARE_DYNAMIC_DELEGATE_RetVal(bool, FStateTransitionRule);

DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(bool, FEventHandlerRule, FSNGEvent&, Event);

/*
USTRUCT()
struct FStateTransition
{
	GENERATED_BODY()

	FName DestinationState;
	FStateTransitionRule TransitionRule;

	FStateTransition()
		: DestinationState(NAME_None)
	{}
};
*/

USTRUCT()
struct FEventHandler
{
	GENERATED_BODY()

	FName DestinationState;
	FEventHandlerRule HandlerRule;

	FEventHandler()
		: DestinationState(NAME_None)
	{}
};

/**
 * 
 */
UCLASS(Blueprintable)
class SWORDNGUN_API USNGState : public UObject
{
	GENERATED_BODY()
	
	public: 
    	USNGState();

		UFUNCTION(BlueprintCallable)
		void RegisterTransition(FName DestState, FName TransitionRuleFunctionName);
	
		UFUNCTION(BlueprintCallable)
		void RegisterEventHandler(FName DestState, ESNGEventType EventType, FName EventHandlerFunctionName);
	
		FName GetName();

		float GetTimeInState();

		bool CanTransitionToItself();
	
		UFUNCTION(BlueprintCallable)
	    AActor* GetOwner();

		void SetOwner(AActor* StateOwner);
	
		TArray<TSubclassOf<USNGState>> GetSubStateClasses();

		void AddSubState(USNGState* SubState);

		// returns name of the next state if event triggers a state transition
		FName GetNextStateFromEvent(FSNGEvent& Event);
	
    	// executes transitions rules for this state to determine what substate 
    	FName GetNextState();
	
		void CreateState();
	
		USNGState* EnterState();

		void ExitState();
	
		void UpdateState(float DeltaTime);
    
    protected:
    
    	UPROPERTY(EditDefaultsOnly)
    	FName Name;

		UPROPERTY(BlueprintReadOnly)
		float TimeInState;

		UPROPERTY(EditDefaultsOnly)
		bool bCanTransitionToItself;

		UPROPERTY(EditDefaultsOnly, Category="Sub states", meta = (ClampMin = -1))
		int32 DefaultSubStateIndex;

		UPROPERTY(EditDefaultsOnly, Category="Sub states")
    	TArray<TSubclassOf<USNGState>> SubStateClasses;
	
		TArray<USNGState*> SubStates;
	
		AActor* Owner;
	
		USNGState* Parent;

		// NOTE(kevin): I don't think this needs to be a map
    	TMap<FName, FStateTransitionRule> Transitions;

		TMap<ESNGEventType, TArray<FEventHandler>> Handlers; 
	
		UFUNCTION(BlueprintImplementableEvent)
		void OnCreateState();
		
		UFUNCTION(BlueprintImplementableEvent)
	    void OnEnterState();
	    
		UFUNCTION(BlueprintImplementableEvent)
	    void OnExitState();
	    
		UFUNCTION(BlueprintImplementableEvent)
	    void OnUpdateState(float DeltaTime);
};
