// Fill out your copyright notice in the Description page of Project Settings.


#include "Characters/Components/ShootingComponent.h"

// Sets default values for this component's properties
UShootingComponent::UShootingComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	// ...
}


// Called when the game starts
void UShootingComponent::BeginPlay()
{
	Super::BeginPlay();

    PlayerCharacter = Cast<AExoPlayerCharacter>(GetOwner());
}


void UShootingComponent::Shoot()
{
    if (!IsValid(CurrentGun) || CurrentGun->CurrentAmmo == 0 || bIsReloading || !bCanShoot) return;

    bCanShoot = false;
    CurrentGun->CurrentAmmo--;
    
    AActor* HitActor = ExecuteLineTrace(CurrentGun->MaxRange);
    if (HitActor)
    {
        IDamageable::Execute_TakeDamage(HitActor, CurrentGun->DamageValue);

        UE_LOG(LogTemp, Display, TEXT("Shoot. Ammo: %d/%d"), CurrentGun->CurrentAmmo, CurrentGun->MaxAmmo);    // Docelowo tutaj wywołanie UI aktualizujące stan ammo
    }

    PlayerCharacter->GetWorldTimerManager().SetTimer(ShootCooldownTimer, this, &UShootingComponent::ResetFireCooldown, CurrentGun->FireRateCooldown, false);

    // Odrzut
    float RecoilPitch = FMath::RandRange(-1.0f, -0.5f);
    float RecoilYaw = FMath::RandRange(-0.5f, 0.5f);
    
    PlayerCharacter->AddControllerPitchInput(RecoilPitch * CurrentGun->RecoilForceMultiplier);
    PlayerCharacter->AddControllerYawInput(RecoilYaw * CurrentGun->RecoilForceMultiplier);
}

void UShootingComponent::MeleAttack()
{
    AActor* HitActor = ExecuteLineTrace(MeleRange);
    if (HitActor)
    {
        IDamageable::Execute_TakeDamage(HitActor, MeleDamageValue);
    }
}

AActor* UShootingComponent::ExecuteLineTrace(float LineRange)
{
    FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
    FVector ViewLocation;
    FRotator ViewRotation;
    PlayerCharacter->GetController()->GetPlayerViewPoint(ViewLocation, ViewRotation);

    FVector EndVector = ViewLocation + ForwardVector * LineRange;

    FHitResult Hit;
    FCollisionQueryParams QueryParams;
    QueryParams.AddIgnoredActor(PlayerCharacter);

    // DEBUG
    if (bShowDebugLine)
        DrawDebugLine(GetWorld(), ViewLocation, EndVector, FColor::Red, false, 1.0f, 0, 1.0f);

    if (GetWorld()->LineTraceSingleByChannel(Hit, ViewLocation, EndVector, ECC_Visibility, QueryParams) &&
        IsValid(Hit.GetActor()) && Hit.GetActor()->Implements<UDamageable>())
    {
        return Hit.GetActor();
    }

    return nullptr;
}

void UShootingComponent::Reload()
{
    if (!IsValid(CurrentGun) || bIsReloading) return;

    bIsReloading = true;

    CurrentGun->CurrentAmmo = CurrentGun->MaxAmmo;
    PlayerCharacter->GetWorldTimerManager().SetTimer(ReloadTimer, this, &UShootingComponent::ReloadCompleted, CurrentGun->ReloadTime, false);

    UE_LOG(LogTemp, Display, TEXT("Reloaded. Ammo: %d/%d"), CurrentGun->CurrentAmmo, CurrentGun->MaxAmmo);    // Docelowo tutaj wywo�anie UI aktualizuj�ce stan ammo
}

void UShootingComponent::PickUpGun(AGunBase* gunItem)
{
    if (IsValid(CurrentGun) && IsValid(SecondaryGun))
        DropGun();

    AGunBase* NewGun = NewObject<AGunBase>();
    
    NewGun->MaxRange = gunItem->MaxRange;
    NewGun->DamageValue = gunItem->DamageValue;
    NewGun->FireRateCooldown = gunItem->FireRateCooldown;
    NewGun->RecoilForceMultiplier = gunItem->RecoilForceMultiplier;
    NewGun->ReloadTime = gunItem->ReloadTime;
    NewGun->CurrentAmmo = gunItem->CurrentAmmo;
    NewGun->MaxAmmo = gunItem->MaxAmmo;
    NewGun->SceneItemClass = gunItem->GetClass();

    if (IsValid(CurrentGun))
        SecondaryGun = NewGun;
    else
        CurrentGun = NewGun;
}

void UShootingComponent::DropGun()
{
    if (!IsValid(CurrentGun)) return;

    FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
    FVector PlayerPos = PlayerCharacter->GetActorLocation();
    FVector DroppedGunPos = PlayerPos + (ForwardVector * DropGunRange);

    FTransform DroppedGunTransform = PlayerCharacter->GetActorTransform();
    DroppedGunTransform.SetLocation(DroppedGunPos);
    
    AGunBase* DroppedGun = GetWorld()->SpawnActor<AGunBase>(CurrentGun->SceneItemClass, DroppedGunTransform);

    if (DroppedGun)
    {
        DroppedGun->MaxRange = CurrentGun->MaxRange;
        DroppedGun->DamageValue = CurrentGun->DamageValue;
        DroppedGun->FireRateCooldown = CurrentGun->FireRateCooldown;
        DroppedGun->RecoilForceMultiplier = CurrentGun->RecoilForceMultiplier;
        DroppedGun->ReloadTime = CurrentGun->ReloadTime;
        DroppedGun->CurrentAmmo = CurrentGun->CurrentAmmo;
        DroppedGun->MaxAmmo = CurrentGun->MaxAmmo;
        
        CurrentGun->Destroy();
        CurrentGun = nullptr;
    }
}

void UShootingComponent::ResetFireCooldown()
{
    bCanShoot = true;
}

void UShootingComponent::ReloadCompleted()
{
    bIsReloading = false;
}

void UShootingComponent::SelectGun(bool bSelectFirstSlot)
{
    if (bSelectFirstSlot != bIsFirstGunSelected)
        SwitchGun();
}

void UShootingComponent::SwitchGun()
{
    AGunBase* temp = CurrentGun;
    CurrentGun = SecondaryGun;
    SecondaryGun = temp;

    bIsFirstGunSelected = !bIsFirstGunSelected;

    // Debug info
    if (bIsFirstGunSelected)
    {
        UE_LOG(LogTemp, Display, TEXT("Zmiana broni na broń 1"));
    }
    else
    {
        UE_LOG(LogTemp, Display, TEXT("Zmiana broni na broń 2"));
    }
}

// Called every frame
void UShootingComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
}

