// Project Sword & Gun Copyright © 2021 Kevin Poretti

#pragma once

#include "CoreMinimal.h"
#include "Components/SNGCharacterMovementComponent.h"

#include "Components/SNGHealthComponent.h"
#include "Components/SNGStateMachineComponent.h"
#include "GameFramework/Character.h"
#include "Interfaces/SNGEventProcessorInterface.h"
#include "Interfaces/SNGWeaponUserInterface.h"

#include "SNGCharacterBase.generated.h"

UCLASS()
class SWORDNGUN_API ASNGCharacterBase : public ACharacter, public ISNGEventProcessorInterface, public ISNGWeaponUserInterface
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ASNGCharacterBase(const FObjectInitializer& ObjectInitializer);
	
	/*********************************************************************
	 *	Flags
	 ********************************************************************/
	
	UFUNCTION(BlueprintCallable)
	void DisableAllActions();

	UFUNCTION(BlueprintCallable)
	void EnableAllActions();

	// NOTE(kevin): should be a blueprint setter but I could not get that working for the life of me
	UFUNCTION(BlueprintCallable)
	void SetCanMove(bool CanMove);
	
	UFUNCTION(BlueprintGetter)
	bool CanMove();

	// NOTE(kevin): should be a blueprint setter but I could not get that working for the life of me
	// should also probably be a protagonist/player character specific thing
	UFUNCTION(BlueprintCallable)
	void SetCanCharacterJump(bool CanJump);
	
	UFUNCTION(BlueprintGetter)
	bool CanCharacterJump();

	// NOTE(kevin): should be a blueprint setter but I could not get that working for the life of me
	UFUNCTION(BlueprintCallable)
	void SetCanAttack(bool CanAttack);
	
	UFUNCTION(BlueprintGetter)
	bool CanAttack();

	// NOTE(kevin): should be a blueprint setter but I could not get that working for the life of me
	// should also probably be a protagonist/player character specific thing
	UFUNCTION(BlueprintCallable)
	void SetCanDodge(bool CanDodge);
	
	UFUNCTION(BlueprintGetter)
	bool CanDodge();

protected:
	UPROPERTY(BlueprintReadOnly)
	bool bCanMove;
	
	UPROPERTY(BlueprintReadOnly)
	bool bCanJump;

	UPROPERTY(BlueprintReadOnly)
	bool bCanAttack;
	
	UPROPERTY(BlueprintReadOnly)
	bool bCanDodge;
	
	/*********************************************************************
	 *	Movement
	 ********************************************************************/

public:
	
	UFUNCTION(BlueprintCallable, Category="Movement")
	void SetIgnoreMovementInput(bool IsIgnored);

	UFUNCTION(BlueprintCallable, Category="Movement")
	FORCEINLINE class USNGCharacterMovementComponent* GetSNGCharacterMovementComponent() const
	{
		return SNGCharacterMovementComponent;
	} 

protected:
	USNGCharacterMovementComponent* SNGCharacterMovementComponent;

public:
	/*********************************************************************
	 *	Event processing interface
	 ********************************************************************/
	// event processing 
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	void PushEvent(FSNGEvent Event);
	
	/**
	* The state machine will be handling most if not all of the states
	* we simply wrap the state machine's push event implementation since most
	* characters that will want to push events to another character will have a reference
	* to the character itself rather than the state machine component
	*/ 
	virtual void PushEvent_Implementation(FSNGEvent Event);

	
	/*********************************************************************
	 *	Weapons
	 ********************************************************************/
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	ASNGWeaponBase* GetCurrentWeapon();

	virtual ASNGWeaponBase* GetCurrentWeapon_Implementation();

	/*********************************************************************
	 *	Damage and hits 
	 ********************************************************************/
	// damage and related 
	UFUNCTION(BlueprintCallable)
	void ApplyHitStop(float HitStopTime, float HitSlowTime);
	
	virtual void ReceiveHit(FSNGHitData const& HitData, AController* EventInstigator, AActor* DamageCauser);
	
	virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;

protected:
	bool bIsInHitStop;
	
	float CurrHitStopTime;

	float CurrHitSlowTime;

	/*********************************************************************
	 *	Rotate towards target
	 ********************************************************************/
public:
	UFUNCTION(BlueprintCallable)
	void SetupRotateTowardsTarget(FRotator TargetRotation, float DegreesPerSecond, float MaxRotation);

	UFUNCTION(BlueprintCallable)
	void RotateTowardsTarget(float DeltaTime);

protected:
	FRotator InitialRot;
	
	FRotator TargetRot;
	
	float DegPerSecond;

	float MaxRot;

	float RotateTime;

	float RotateTimeElapsed;
	
	/*********************************************************************
	 *	Components
	 ********************************************************************/
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
	USNGStateMachineComponent* StateMachineComponent;
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
	USNGHealthComponent* HealthComponent;
	
	virtual void Tick(float DeltaSeconds) override;

	virtual void PostInitializeComponents() override;
};
