// Copyright Pacificao. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "AgrarianTypes.h"
#include "AgrarianSurvivalComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianSurvivalChangedSignature, const FAgrarianSurvivalSnapshot&, Snapshot);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAgrarianDeathStateChangedSignature, bool, bIsDead, FName, DeathReason);

UCLASS(ClassGroup = (Agrarian), BlueprintType, Blueprintable, meta = (BlueprintSpawnableComponent))
class UAgrarianSurvivalComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UAgrarianSurvivalComponent();

	virtual void BeginPlay() override;
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Survival")
	FAgrarianSurvivalChangedSignature OnSurvivalChanged;

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Survival")
	FAgrarianDeathStateChangedSignature OnDeathStateChanged;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, ReplicatedUsing = OnRep_Survival, Category = "Agrarian|Survival")
	FAgrarianSurvivalSnapshot Survival;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, ReplicatedUsing = OnRep_CareHistory, Category = "Agrarian|Survival")
	FAgrarianCareHistorySnapshot CareHistory;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|Survival|Shelter")
	float CurrentWeatherProtection = 0.0f;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|Survival|Weather Exposure")
	float CurrentWeatherExposureMultiplier = 1.0f;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|Survival|Weather Exposure")
	float CurrentWeatherTemperatureOffsetC = 0.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float HungerDecayPerMinute = 0.55f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float ThirstDecayPerMinute = 0.85f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float StaminaRecoveryPerSecond = 14.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float ExhaustionGainPerLowStaminaSecond = 0.35f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float ExhaustionRecoveryPerSecond = 0.08f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0", ClampMax = "100"))
	float LowStaminaExhaustionThreshold = 20.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float StarvationDamagePerMinute = 3.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float DehydrationDamagePerMinute = 5.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float ColdDamagePerMinute = 4.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float SicknessDamagePerMinute = 1.5f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float SicknessRecoveryPerSecond = 0.02f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float BleedingDamagePerMinute = 2.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float BleedingExhaustionPerSecond = 0.04f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Survival|Rates", meta = (ClampMin = "0"))
	float SprainExhaustionPerSecond = 0.03f;

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

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	bool IsDead() const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ApplyDamage(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void RestoreHealth(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void MarkDead(FName Reason);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void Revive(float HealthAmount = 100.0f);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddFood(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddWater(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddWarmth(float DegreesCelsius);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddInjury(float Severity);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ReduceInjury(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddBleeding(float Severity);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ReduceBleeding(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddSprain(float Severity);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ReduceSprain(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddSickness(float Severity);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ReduceSickness(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ApplySavedState(const FAgrarianSurvivalSnapshot& SavedSurvival, const FAgrarianCareHistorySnapshot& SavedCareHistory);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void SpendStamina(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void AddExhaustion(float Amount);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Survival")
	void ReduceExhaustion(float Amount);

	UFUNCTION(BlueprintPure, Category = "Agrarian|Survival|Shelter")
	float CalculateCurrentWeatherProtection() const;

	UFUNCTION(BlueprintPure, Category = "Agrarian|Survival|Weather Exposure")
	float CalculateCurrentWeatherExposureMultiplier() const;

	UFUNCTION(BlueprintPure, Category = "Agrarian|Survival|Weather Exposure")
	float CalculateCurrentWeatherTemperatureOffsetC() const;

protected:
	UFUNCTION()
	void OnRep_Survival();

	UFUNCTION()
	void OnRep_CareHistory();

	void ClampSurvival();
	void ClampCareHistory();
	void UpdateDeathState();
	void BroadcastSurvivalChanged();

	bool bLastBroadcastDeathState = false;
	FName LastBroadcastDeathReason = NAME_None;
};
