// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"

#include "InputBufferComponent.generated.h"

DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferComponent, Log, All);

DECLARE_DELEGATE_TwoParams(FNewComboInput, const class UComboInputAsset*, const EComboActionTriggerEvent &);


/**
 * Subsystem that handles input buffering, and passing the resulting actions to the player's ComboManagerComponent.
 */
UCLASS()
class COMBOINPUT_API UInputBufferComponent : public UEnhancedInputComponent
{
	GENERATED_BODY()

public:
	virtual void BeginPlay() override;

	UFUNCTION(BlueprintCallable)
		void LockComboInput(const class UComboInputAsset *Input);
	UFUNCTION(BlueprintCallable)
		void UnlockComboInput(const class UComboInputAsset *Unlocked);

private:
	void AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action);
	void ExpireAction(const FInputActionValue &Value, const class UInputAction *Action);

	void ActivateComboInput(const class UComboInputAsset *ComboInput);
	void HoldComboInput(const class UComboInputAsset *ComboInput);

	void ClearMultiPresses();
	void ExpireBufferedActions();

	TObjectPtr<class UEnhancedInputComponent> EnhancedInputComponent;

	// Currently active combo input.
	TObjectPtr<const class UComboInputAsset> InputBufferActive;

	// Combo input held until the current input has expired.
	TObjectPtr<const class UComboInputAsset> InputBufferHold;

	// Set of currently locked actions; will not be activated until an unlock signal is received.
	TSet<TObjectPtr<const class UComboInputAsset>> LockedComboInputs;

	// A local backup of the global setting containing the list of combo inputs to respond to.
	TSet<TObjectPtr<const UComboInputAsset>> ComboInputList;

	TSet<const class UInputAction*> MostRecentActions;
	TSet<const class UInputAction*> ExpiringActions;

	FNewComboInput OnNewComboInput;

	FTimerHandle MultiPressTimerHandle;
	FTimerHandle InputReleaseExpirationTimerHandle;
	FTimerHandle ForceUnlockTimerHandle;
};
