// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — BPC_DamageReceptionSystem Implementation

#include "Weapons/BPC_DamageReceptionSystem.h"
#include "Player/BPC_HealthSystem.h"
#include "Weapons/BPC_ShieldDefenseSystem.h"
#include "Weapons/BPC_HitReactionSystem.h"

DEFINE_LOG_CATEGORY_STATIC(LogFrameworkDamage, Log, All);

UBPC_DamageReceptionSystem::UBPC_DamageReceptionSystem()
{
	PrimaryComponentTick.bCanEverTick = false;
}

// ============================================================================
// Damage Calculation — Hot Path
// ============================================================================

float UBPC_DamageReceptionSystem::ApplyDamage(float RawDamage, AActor* DamageCauser,
	FGameplayTag DamageType, FVector HitLocation, FVector HitDirection)
{
	if (RawDamage <= 0.0f || !DamageType.IsValid())
	{
		return 0.0f;
	}

	// Step 1: Calculate damage multiplier from modifiers.
	float Multiplier = GetDamageMultiplier(DamageType);

	// Step 2: Apply resistance.
	float Resistance = CalculateResistance(DamageType);
	float ResistedAmount = RawDamage * Resistance;

	// Step 3: Calculate final damage.
	float FinalDamage = (RawDamage * Multiplier) - ResistedAmount;
	FinalDamage = FMath::Max(FinalDamage, 0.0f); // No negative damage.

	// Check for flat reduction modifiers.
	for (const FDamageModifier& Mod : DamageModifiers)
	{
		if (Mod.DamageType == DamageType && Mod.bFlatReduction)
		{
			FinalDamage = FMath::Max(FinalDamage - Mod.FlatReduction, 1.0f); // Minimum 1 damage.
		}
	}

	// Step 4: Apply shield absorption if available.
	if (CachedShieldSystem)
	{
		// Shield absorbs damage before health.
		// FinalDamage = CachedShieldSystem->AbsorbDamage(FinalDamage);
	}

	// Step 5: Route to health system.
	if (CachedHealthSystem)
	{
		// CachedHealthSystem->ApplyHealthDamage(FinalDamage);
	}

	// Step 6: Evaluate hit reaction.
	EvaluateHitReaction(FinalDamage, DamageCauser, HitDirection);

	// Step 7: Broadcast.
	OnDamageReceived.Broadcast(RawDamage, FinalDamage, DamageCauser, DamageType, HitLocation);

	if (ResistedAmount > 0.0f)
	{
		OnDamageResisted.Broadcast(ResistedAmount, DamageType,
			FString::Printf(TEXT("Resistance: %.1f%%"), Resistance * 100.0f));
	}

	UE_LOG(LogFrameworkDamage, Verbose, TEXT("ApplyDamage — Raw: %.1f → Final: %.1f (Type: %s, Resist: %.1f%%)"),
		RawDamage, FinalDamage, *DamageType.GetTagName().ToString(), Resistance * 100.0f);

	return FinalDamage;
}

float UBPC_DamageReceptionSystem::CalculateResistance(FGameplayTag DamageType) const
{
	if (!DamageType.IsValid())
	{
		return 0.0f;
	}

	// Base resistance + equipment-specific bonuses.
	float TotalResistance = BaseResistance;

	if (EquipmentConfig)
	{
		// EquipmentConfig would provide per-damage-type resistance values.
		// TotalResistance += EquipmentConfig->GetResistance(DamageType);
	}

	return FMath::Clamp(TotalResistance, 0.0f, 1.0f);
}

float UBPC_DamageReceptionSystem::GetDamageMultiplier(FGameplayTag DamageType) const
{
	if (!DamageType.IsValid())
	{
		return 1.0f;
	}

	for (const FDamageModifier& Mod : DamageModifiers)
	{
		if (Mod.DamageType == DamageType && !Mod.bFlatReduction)
		{
			return Mod.Multiplier;
		}
	}

	return 1.0f; // No modifier — normal damage.
}

// ============================================================================
// Hit Reaction
// ============================================================================

void UBPC_DamageReceptionSystem::EvaluateHitReaction(float FinalDamage, AActor* DamageCauser,
	FVector HitDirection)
{
	if (FinalDamage >= KnockdownThreshold)
	{
		UE_LOG(LogFrameworkDamage, Log, TEXT("EvaluateHitReaction — Knockdown! (%.1f damage)"), FinalDamage);
		OnKnockedDown.Broadcast(DamageCauser, FinalDamage);
	}
	else if (FinalDamage >= StaggerThreshold)
	{
		UE_LOG(LogFrameworkDamage, Verbose, TEXT("EvaluateHitReaction — Stagger (%.1f damage)"), FinalDamage);
		OnStaggered.Broadcast(DamageCauser, FinalDamage);
	}

	// Route to dedicated hit reaction system for animation selection.
	if (CachedHitReactionSystem)
	{
		// CachedHitReactionSystem->PlayHitReaction(FinalDamage, HitDirection, DamageCauser);
	}
}
