// Copyright (c) 2026 GregOrigin. All Rights Reserved.
#include "ARPGCharacter.h"
#include "Net/UnrealNetwork.h"
#include "Engine/World.h"
#include "CollisionQueryParams.h"

ARPGCharacter::ARPGCharacter()
{
	MaxHealth = 100.0f;
	Health = MaxHealth;
	AttackPower = 10.0f;
	Level = 1;
	Experience = 0;
	InventoryComponent = CreateDefaultSubobject<URPGInventoryComponent>(TEXT("Inventory"));
	bReplicates = true;
}

void ARPGCharacter::OnRep_Health()
{
	OnHealthChanged.Broadcast(Health, MaxHealth);
}

void ARPGCharacter::GainExperience(int32 Amount)
{
	Experience += Amount;
	const int32 XPThreshold = Level * 100;
	if (Experience >= XPThreshold)
	{
		Experience -= XPThreshold;
		Level++;
		OnLevelUp.Broadcast(Level);
	}
}

float ARPGCharacter::GetHealthPercent() const
{
	return (MaxHealth > 0.f) ? Health / MaxHealth : 0.f;
}

bool ARPGCharacter::IsAlive() const
{
	return Health > 0.f;
}

void ARPGCharacter::ReceiveDamage_Implementation(float Amount)
{
	if (!IsAlive()) return;
	Health = FMath::Clamp(Health - Amount, 0.f, MaxHealth);
	OnHealthChanged.Broadcast(Health, MaxHealth);
	if (!IsAlive())
	{
		OnDeath.Broadcast();
	}
	ClientReceiveDamage(Amount);
	NetMulticastPlayHitEffect();
}

float ARPGCharacter::GetCurrentHealth_Implementation() const
{
	return Health;
}

bool ARPGCharacter::GetIsAlive_Implementation() const
{
	return IsAlive();
}

void ARPGCharacter::CheatAttack()
{
	ServerRequestAttack();
}

void ARPGCharacter::CheatGainXP(int32 Amount)
{
	GainExperience(Amount);
}

void ARPGCharacter::CheatAddItem()
{
	if (!InventoryComponent) return;
	FRPGItemData TestItem;
	TestItem.ItemName = TEXT("Test Sword");
	TestItem.ItemWeight = 5.0f;
	TestItem.StackCount = 1;
	TestItem.MaxStackSize = 1;
	TestItem.Rarity = EItemRarity::Rare;
	bool bAdded = InventoryComponent->AddItem(TestItem);
	UE_LOG(LogTemp, Log, TEXT("AddItem: %s (count: %d, weight: %.1f)"),
		bAdded ? TEXT("success") : TEXT("failed"),
		InventoryComponent->GetItemCount(), InventoryComponent->CurrentWeight);
}

void ARPGCharacter::CheatHeal()
{
	Health = MaxHealth;
	OnHealthChanged.Broadcast(Health, MaxHealth);
	UE_LOG(LogTemp, Log, TEXT("Healed to full health: %.1f"), Health);
}

void ARPGCharacter::CheatNuke()
{
	FVector Start = GetActorLocation();
	TArray<FHitResult> OutHits;
	FCollisionShape MyColSphere = FCollisionShape::MakeSphere(1000.f);
	FCollisionQueryParams Params;
	Params.AddIgnoredActor(this);
	if (GetWorld()->SweepMultiByChannel(OutHits, Start, Start, FQuat::Identity, ECC_Pawn, MyColSphere, Params))
	{
		for (const FHitResult& Hit : OutHits)
		{
			if (AActor* Target = Hit.GetActor())
			{
				if (Target->Implements<UDamageable>())
				{
					IDamageable::Execute_ReceiveDamage(Target, 9999.0f);
				}
			}
		}
	}
	UE_LOG(LogTemp, Warning, TEXT("CheatNuke executed. AoE Damage applied."));
}

void ARPGCharacter::CheatGodMode()
{
	Health = 999999.0f;
	MaxHealth = 999999.0f;
	AttackPower = 99999.0f;
	OnHealthChanged.Broadcast(Health, MaxHealth);
	UE_LOG(LogTemp, Warning, TEXT("God Mode Activated. Health: %.1f, Attack: %.1f"), Health, AttackPower);
}

void ARPGCharacter::ServerRequestAttack_Implementation()
{
	FHitResult Hit;
	FVector Start = GetActorLocation();
	FVector End = Start + GetActorForwardVector() * 300.f;
	FCollisionQueryParams Params;
	Params.AddIgnoredActor(this);
	if (GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Pawn, Params))
	{
		if (AActor* Target = Hit.GetActor())
		{
			if (Target->Implements<UDamageable>())
			{
				IDamageable::Execute_ReceiveDamage(Target, AttackPower);
			}
		}
	}
}

void ARPGCharacter::ClientReceiveDamage_Implementation(float Amount)
{
	UE_LOG(LogTemp, Log, TEXT("%s received %.1f damage (client feedback)"), *GetName(), Amount);
}

void ARPGCharacter::NetMulticastPlayHitEffect_Implementation()
{
	UE_LOG(LogTemp, Log, TEXT("%s: hit effect played"), *GetName());
}

void ARPGCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(ARPGCharacter, Health);
}