#pragma once

#include "CoreMinimal.h"
#include "AIInteractableTargetInterface.h"
#include "AIPointOfInterestTargetInterface.h"
#include "CharmAttachable.h"
#include "HookAnalyticEvents.h"
#include "Interactable.h"
#include "UObject/NoExportTypes.h"
#include "GameplayTagContainer.h"
#include "DBDTunableRowHandle.h"
#include "AnimationMontageDescriptor.h"
#include "MeatHook.generated.h"

class UDBDClipRegionComponent;
class UCharacterPusherComponent;
class UCapsuleComponent;
class UPollableEventListener;
class ASurvivor;
class ADBDPlayer;
class UInteractor;
class UChargeableInteractionDefinition;
class USceneComponent;
class AEntity;
class UAIPerceptionStimuliSourceComponent;
class UMapActorComponent;
class ACharacter;
class UChargeableComponent;
class UMontagePlayer;
class UAkComponent;
class AKiller;
class UBoxComponent;
class UPrimitiveComponent;
class UShapeComponent;
class UHookableComponent;

UCLASS(Blueprintable)
class DEADBYDAYLIGHT_API AMeatHook : public AInteractable, public IAIInteractableTargetInterface, public IAIPointOfInterestTargetInterface, public ICharmAttachable, public IHookAnalyticEvents
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool WasSurvivorStruggleCancelled;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool IsSacrificeEnabled;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FVector AIInteractionOffset;

protected:
	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced)
	TArray<UDBDClipRegionComponent*> ClipRegions;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool IsSurvivorStruggling;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool IsInBasement;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool IsBreakable;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool IsSabotageable;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool CanBeScourgeHook;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FGameplayTag HookIdentityTag;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool SnapHookedCharacter;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool FullyHooked;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float _struggleThreshold;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced)
	UCharacterPusherComponent* _characterPusher;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced)
	UCapsuleComponent* _slasherCollisionBlocker;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced)
	UCapsuleComponent* _conditionalSlasherCollisionBlocker;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FGameplayTagContainer _conditionalSlasherCollisionBlockerPresenceTags;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FGameplayTagContainer _stateTagsToApplyOnBeginPlay;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FDBDTunableRowHandle _sacrificedHookRespawnDuration;

private:
	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced, meta=(AllowPrivateAccess=true))
	UPollableEventListener* _eventListener;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, meta=(AllowPrivateAccess=true))
	ASurvivor* _hookedSurvivor;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, meta=(AllowPrivateAccess=true))
	ADBDPlayer* _hookBreakerPlayer;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, meta=(AllowPrivateAccess=true))
	TSet<ASurvivor*> _campersThatSabotagedMeatHook;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced, meta=(AllowPrivateAccess=true))
	UInteractor* _mainInteractor;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced, meta=(AllowPrivateAccess=true))
	UChargeableInteractionDefinition* _unhook;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced, meta=(AllowPrivateAccess=true))
	USceneComponent* _camperHookedSnapTransform;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, meta=(AllowPrivateAccess=true))
	AEntity* _entity;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced, meta=(AllowPrivateAccess=true))
	UAIPerceptionStimuliSourceComponent* _perceptionStimuliComponent;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, meta=(AllowPrivateAccess=true))
	ADBDPlayer* _interactingPlayer;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Transient, Instanced, meta=(AllowPrivateAccess=true))
	UMapActorComponent* _cachedMapActor;

protected:
	UFUNCTION(BlueprintCallable)
	void UpdateSlasherBlockerCollision();

public:
	UFUNCTION(BlueprintCallable)
	void SetMapActor(UMapActorComponent* value);

	UFUNCTION(BlueprintCallable)
	void SetIsBeingSabotaged(bool isBeingSabotaged);

	UFUNCTION(BlueprintCallable)
	void SetInteractingPlayer(ADBDPlayer* interactingPlayer);

protected:
	UFUNCTION(BlueprintCallable)
	void SetEntity(AEntity* entity);

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnTickStruggle(float deltaTime);

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, BlueprintCosmetic)
	void OnStruggleSkillCheckFailed_Cosmetic();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnStruggleExit();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnStruggleEnter();

private:
	UFUNCTION(BlueprintCallable)
	void OnStopPushingPlayer(ACharacter* character);

	UFUNCTION(BlueprintCallable)
	void OnStartPushingPlayer(ACharacter* character);

protected:
	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnSacrificeOut();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnSacrificeIn();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnReactionIn();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnReaction();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnOwnerReplicated();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnHookingExit();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnHookingEnter();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnHookedSurvivorChanged(ASurvivor* before, ASurvivor* after);

	UFUNCTION(BlueprintCallable)
	void OnHookedSurvivorAttacked();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnHookedIdle();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnHookedExit();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnHookedEnter();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void OnAutoRepair();

private:
	UFUNCTION(BlueprintCallable, NetMulticast, Reliable)
	void Multicast_SetIsSacrificed(bool isSacrificed);

	UFUNCTION(BlueprintCallable, NetMulticast, Reliable)
	void Multicast_SetIsSabotaged(bool setIsSabotaged, ADBDPlayer* hookBreaker, bool useCamperHookRespawnDurationModifiers, float overrideBaseHookRespawnDuration);

	UFUNCTION(BlueprintCallable, NetMulticast, Reliable)
	void Multicast_SetIsBrokenFromUnhook(bool setIsBrokendFromUnhook, ADBDPlayer* hookBreaker, float overrideBaseHookRespawnDuration);

protected:
	UFUNCTION(BlueprintCallable, NetMulticast, Reliable)
	void Multicast_SetHookedSurvivor(ASurvivor* survivor);

	UFUNCTION(BlueprintCallable, NetMulticast, Reliable)
	void Multicast_RefreshCharmCustomization();

public:
	UFUNCTION(BlueprintCallable, NetMulticast, Reliable)
	void Multicast_EscapeAttemptResult(ADBDPlayer* player, bool result);

	UFUNCTION(BlueprintCallable)
	void Local_MoveSurvivorToHook(ASurvivor* survivor, const float duration);

	UFUNCTION(BlueprintPure)
	FAnimationMontageDescriptor GetUnhookOutMontageDescriptor() const;

	UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
	UChargeableInteractionDefinition* GetUnhookInteraction() const;

	UFUNCTION(BlueprintPure)
	FAnimationMontageDescriptor GetUnhookInMontageDescriptor() const;

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	UChargeableComponent* GetUnhookChargeableComponent();

	UFUNCTION(BlueprintPure)
	float GetStruggleThreshold() const;

	UFUNCTION(BlueprintPure)
	float GetStrugglePercent() const;

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	TArray<USceneComponent*> GetSnapPointsArray() const;

	UFUNCTION(BlueprintPure)
	ADBDPlayer* GetSaboteurPlayer() const;

	UFUNCTION(BlueprintPure)
	float GetSabotageHookRespawnDuration() const;

	UFUNCTION(BlueprintPure)
	UMontagePlayer* GetMontagePlayer() const;

	UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
	UAkComponent* GetMeatHookAkAudioComponent() const;

	UFUNCTION(BlueprintPure, BlueprintNativeEvent)
	UInteractor* GetMainInteractor() const;

protected:
	UFUNCTION(BlueprintPure)
	AKiller* GetKiller() const;

public:
	UFUNCTION(BlueprintPure)
	bool GetIsSacrificed() const;

	UFUNCTION(BlueprintPure)
	bool GetIsSabotaged() const;

	UFUNCTION(BlueprintPure)
	bool GetIsInBasement() const;

	UFUNCTION(BlueprintPure)
	bool GetIsBroken() const;

	UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
	UBoxComponent* GetInteractorZoneComponent() const;

	UFUNCTION(BlueprintPure, BlueprintNativeEvent)
	UPrimitiveComponent* GetInteractorPrimitiveComponent() const;

	UFUNCTION(BlueprintPure)
	ADBDPlayer* GetInteractingPlayer() const;

protected:
	UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
	FVector GetHookPosition() const;

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	UShapeComponent* GetHookObstacleZoneComponent() const;

public:
	UFUNCTION(BlueprintPure)
	ASurvivor* GetHookedSurvivor() const;

	UFUNCTION(BlueprintPure)
	UHookableComponent* GetHookableComponentOfHookedActor() const;

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	UChargeableInteractionDefinition* GetEscapeHookInteraction() const;

	UFUNCTION(BlueprintPure)
	UCharacterPusherComponent* GetCharacterPusher() const;

	UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
	USceneComponent* GetCamperUnkookFocalPointTransform() const;

	UFUNCTION(BlueprintPure, BlueprintNativeEvent)
	USceneComponent* GetCamperHookedSnapTransform() const;

	UFUNCTION(BlueprintPure=false, BlueprintCallable, BlueprintImplementableEvent)
	void FireHookSoundEvent(const FName NoiseRangeTunable, const ADBDPlayer* soundInstigator) const;

	UFUNCTION(BlueprintCallable)
	void DebugHookedSurvivor(ASurvivor* expectedSurvivor) const;

protected:
	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, BlueprintCosmetic)
	void Cosmetic_StopScourgeHookVFX();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, BlueprintCosmetic)
	void Cosmetic_StartScourgeHookVFX(bool isNewScourgeHook);

public:
	UFUNCTION(BlueprintPure)
	bool CanUnhookSurvivor(const ASurvivor* survivor) const;

	UFUNCTION(BlueprintPure)
	bool CanSurvivorStruggle(ASurvivor* survivor) const;

	UFUNCTION(BlueprintPure)
	bool CanSurvivorAttemptEscape(const ASurvivor* survivor) const;

	UFUNCTION(BlueprintPure)
	bool CanHookSurvivor() const;

	UFUNCTION(BlueprintPure)
	bool CanBeSabotaged() const;

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void BroadcastUnhook(ADBDPlayer* rescuer);

protected:
	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void BP_OnHookInteractionStarted();

public:
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SignalUnhookingEnter();

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SignalUnhookingCharged();

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SignalUnhookingAborted();

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SignalSurvivorAttemptingEscapeAborted();

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SignalSurvivorAttemptingEscape();

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SetIsSacrificed(bool isSacrificed);

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SetIsSabotaged(bool isSabotaged, ADBDPlayer* saboteur, bool useCamperHookRespawnDurationModifiers, float overrideBaseHookRespawnDuration);

	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly)
	void Authority_SetIsBrokenFromUnhook(bool isBrokenFromUnhook, ADBDPlayer* hookBreaker, float overrideBaseHookRespawnDuration);

	UFUNCTION(BlueprintCallable)
	void Authority_SetHookedSurvivor(ASurvivor* survivor);

public:
	AMeatHook();
};

FORCEINLINE uint32 GetTypeHash(const AMeatHook) { return 0; }
