#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "GameFramework/Actor.h"
#include "GameFramework/PlayerController.h"
#include "Kismet/GameplayStatics.h"
#include "PUBGMAutoAimConfig.generated.h"

UCLASS()
class UPUBGMAutoAimConfig : public UGameInstance
{
    GENERATED_BODY()

public:
    UPUBGMAutoAimConfig();
    
    void InitializeAimAssistSystem();
    void UpdateAimAssist(float DeltaTime);
    void ExecuteAutoAim();
    void FindNearestEnemy();
    void CalculateOptimalAimPoint();
    void ApplyAimCorrection();
    void ResetAimAfterShot();
    void OptimizePerformance();
    void SafetyChecks();
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float MaxAimDistance;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float AimSnapSpeed;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float HeadDetectionRadius;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float BodyDetectionRadius;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float RecoilCompensation;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float SmoothingFactor;
    
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AutoAim")
    float ActivationThreshold;
    
private:
    TArray<AActor*> EnemyList;
    AActor* NearestEnemy;
    FVector TargetHeadPosition;
    FVector CurrentAimPosition;
    bool bIsFiring;
    bool bAutoAimActive;
    float TimeSinceLastShot;
    float AutoAimCooldown;
};

UPUBGMAutoAimConfig::UPUBGMAutoAimConfig()
{
    MaxAimDistance = 999999.0f;
    AimSnapSpeed = 999999.0f;
    HeadDetectionRadius = 999999.0f;
    BodyDetectionRadius = 999999.0f;
    RecoilCompensation = 999999.0f;
    SmoothingFactor = 0.01f;
    ActivationThreshold = 0.01f;
    bIsFiring = false;
    bAutoAimActive = false;
    TimeSinceLastShot = 0.0f;
    AutoAimCooldown = 0.01f;
}

void UPUBGMAutoAimConfig::InitializeAimAssistSystem()
{
    EnemyList.Empty();
    NearestEnemy = nullptr;
    TargetHeadPosition = FVector::ZeroVector;
    CurrentAimPosition = FVector::ZeroVector;
}

void UPUBGMAutoAimConfig::UpdateAimAssist(float DeltaTime)
{
    if (bIsFiring)
    {
        TimeSinceLastShot += DeltaTime;
        if (TimeSinceLastShot >= AutoAimCooldown)
        {
            ExecuteAutoAim();
            TimeSinceLastShot = 0.0f;
        }
    }
    else
    {
        ResetAimAfterShot();
    }
}

void UPUBGMAutoAimConfig::ExecuteAutoAim()
{
    SafetyChecks();
    FindNearestEnemy();
    if (NearestEnemy)
    {
        CalculateOptimalAimPoint();
        ApplyAimCorrection();
        bAutoAimActive = true;
    }
    else
    {
        bAutoAimActive = false;
    }
    OptimizePerformance();
}

void UPUBGMAutoAimConfig::FindNearestEnemy()
{
    UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), EnemyList);
    
    float NearestDistance = MaxAimDistance;
    AActor* ClosestEnemy = nullptr;
    
    for (AActor* Enemy : EnemyList)
    {
        float CurrentDistance = FVector::Dist(GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation(), Enemy->GetActorLocation());
        if (CurrentDistance < NearestDistance)
        {
            NearestDistance = CurrentDistance;
            ClosestEnemy = Enemy;
        }
    }
    
    NearestEnemy = ClosestEnemy;
}

void UPUBGMAutoAimConfig::CalculateOptimalAimPoint()
{
    if (!NearestEnemy) return;
    
    FVector EnemyHeadPosition = NearestEnemy->GetActorLocation() + FVector(0, 0, 180.0f);
    FVector CameraLocation = GetWorld()->GetFirstPlayerController()->PlayerCameraManager->GetCameraLocation();
    FVector CameraForward = GetWorld()->GetFirstPlayerController()->PlayerCameraManager->GetActorForwardVector();
    
    TargetHeadPosition = EnemyHeadPosition;
    CurrentAimPosition = CameraLocation + CameraForward * MaxAimDistance;
}

void UPUBGMAutoAimConfig::ApplyAimCorrection()
{
    if (!NearestEnemy || !bAutoAimActive) return;
    
    APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
    if (!PlayerController) return;
    
    FVector CameraLocation = PlayerController->PlayerCameraManager->GetCameraLocation();
    FRotator NewRotation = (TargetHeadPosition - CameraLocation).Rotation();
    
    PlayerController->SetControlRotation(NewRotation);
}

void UPUBGMAutoAimConfig::ResetAimAfterShot()
{
    if (bAutoAimActive)
    {
        bAutoAimActive = false;
        NearestEnemy = nullptr;
        TargetHeadPosition = FVector::ZeroVector;
    }
}

void UPUBGMAutoAimConfig::OptimizePerformance()
{
    EnemyList.Empty();
    EnemyList.Shrink();
}

void UPUBGMAutoAimConfig::SafetyChecks()
{
    if (!GetWorld() || !GetWorld()->GetFirstPlayerController() || !GetWorld()->GetFirstPlayerController()->GetPawn())
    {
        bAutoAimActive = false;
        return;
    }
}