// Copyright Pacificao. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AgrarianInteractable.h"
#include "AgrarianTypes.h"
#include "AgrarianWildlifeBase.generated.h"

class AAgrarianGameCharacter;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianWildlifeStateChangedSignature, EAgrarianWildlifeState, NewState);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianWildlifeHealthChangedSignature, float, Health, float, MaxHealth);

UCLASS(Blueprintable)
class AAgrarianWildlifeBase : public ACharacter, public IAgrarianInteractable
{
	GENERATED_BODY()

public:
	AAgrarianWildlifeBase();

	virtual void Tick(float DeltaSeconds) override;
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Wildlife")
	FAgrarianWildlifeStateChangedSignature OnWildlifeStateChanged;

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Wildlife")
	FAgrarianWildlifeHealthChangedSignature OnWildlifeHealthChanged;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife")
	FName WildlifeId = TEXT("wildlife");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife")
	FText DisplayName;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife")
	EAgrarianWildlifeDisposition Disposition = EAgrarianWildlifeDisposition::Passive;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_WildlifeState, Category = "Agrarian|Wildlife")
	EAgrarianWildlifeState WildlifeState = EAgrarianWildlifeState::Idle;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife", meta = (ClampMin = "1"))
	float MaxHealth = 25.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_Health, Category = "Agrarian|Wildlife", meta = (ClampMin = "0"))
	float Health = 25.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "0"))
	float WanderRadius = 1200.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "0"))
	float WanderSpeed = 180.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "0"))
	float FleeSpeed = 420.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "0"))
	float AggroRadius = 650.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "0"))
	float FleeRadius = 700.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "0.1"))
	float DecisionIntervalSeconds = 2.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement")
	bool bUseNavigationMovement = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "1"))
	float NavigationAcceptanceRadius = 85.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement", meta = (ClampMin = "1"))
	float NavigationRepathDistance = 175.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Movement")
	FVector NavigationProjectionExtent = FVector(500.0f, 500.0f, 900.0f);

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Performance")
	bool bEnablePerformanceLimits = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Performance", meta = (ClampMin = "0"))
	float FullUpdateRadius = 6500.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Performance", meta = (ClampMin = "0.1"))
	float FarUpdateIntervalSeconds = 2.5f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Wildlife|Harvest")
	TArray<FAgrarianItemStack> HarvestYields;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Agrarian|Wildlife|Harvest")
	bool bHarvested = false;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Wildlife")
	bool IsAlive() const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Wildlife")
	void ApplyWildlifeDamage(float Amount, AActor* InstigatorActor);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Wildlife")
	void SetWildlifeState(EAgrarianWildlifeState NewState);

	virtual FText GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const override;
	virtual bool CanInteract_Implementation(const AAgrarianGameCharacter* Interactor) const override;
	virtual void Interact_Implementation(AAgrarianGameCharacter* Interactor) override;

protected:
	virtual void BeginPlay() override;

	UFUNCTION()
	void OnRep_Health();

	UFUNCTION()
	void OnRep_WildlifeState();

	bool ShouldRunServerThink(float DeltaSeconds);
	void ServerThink(float DeltaSeconds);
	void ChooseWanderTarget();
	void MoveTowardTarget();
	bool ChooseReachableWanderTarget(FVector& OutTarget) const;
	bool ProjectPointToNavigation(const FVector& CandidateLocation, FVector& OutProjectedLocation) const;
	bool RequestNavigationMove(const FVector& TargetLocation);
	void ClearNavigationMove();
	void DirectMoveTowardLocation(const FVector& TargetLocation, float MovementSpeed);
	void EnterDeadState();
	AAgrarianGameCharacter* FindNearestPlayer(float Radius) const;
	float GetNearestPlayerDistanceSquared() const;
	bool Harvest(AAgrarianGameCharacter* Interactor);
	void BroadcastHealthChanged();
	void BroadcastStateChanged();

	UPROPERTY()
	FVector SpawnLocation = FVector::ZeroVector;

	UPROPERTY()
	FVector CurrentMoveTarget = FVector::ZeroVector;

	UPROPERTY()
	TObjectPtr<AActor> FocusActor;

	UPROPERTY()
	FVector LastNavigationMoveTarget = FVector::ZeroVector;

	bool bHasNavigationMoveTarget = false;
	float DecisionTimer = 0.0f;
	float ServerThinkAccumulator = 0.0f;
};
