#include "QuantumBallisticTracker.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "DrawDebugHelpers.h"

UQuantumBallisticTracker::UQuantumBallisticTracker() {
  PrimaryComponentTick.bCanEverTick = true;
  PrimaryComponentTick.bStartWithTickEnabled = true;
}

void UQuantumBallisticTracker::BeginPlay() {
  Super::BeginPlay();

  QuantumPredictionMatrix = NewObject<UNeuralNetworkComponent>(this);
  QuantumPredictionMatrix->Initialize(8, 6, 4); 

  DarkMatterVector = FVector(
      FMath::FRandRange(-1.0f, 1.0f),
      FMath::FRandRange(-1.0f, 1.0f),
      FMath::FRandRange(-0.5f, 0.5f)
  ).GetSafeNormal();
}

void UQuantumBallisticTracker::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) {
  Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

  ChronalAccumulator += DeltaTime;

  UpdateQuantumTargetData();
  GenerateHolographicVortex();

  for(auto& QuantumPair : QuantumTargets) {
      FVector Prediction = CalculateQuantumTrajectory(QuantumPair.Key, true);

      ApplyEntanglementField(Prediction, QuantumPair.Key);
      CalculateChronalDistortion(Prediction);
      ProcessNeuralPredictionMatrix(Prediction, QuantumPair.Key);
      AdjustToQuantumEnvironment(Prediction);

      ActivateChaosEngine(Prediction);
      FoldSpaceTime(Prediction);
      ApplyQuantumTunneling(Prediction);
      CalculateDarkMatterInfluence(Prediction);
      ApplyStringTheoryCorrection(Prediction);

      ExecuteQuantumShot(QuantumPair.Key, Prediction);
  }
}

FVector UQuantumBallisticTracker::CalculateQuantumTrajectory(ACharacter* Target, bool bHeadshot) const {
  if(!Target) return FVector::ZeroVector;

  const FQuantumTargetSignature* Signature = QuantumTargets.Find(Target);
  if(!Signature) return Target->GetActorLocation();

  FVector TargetPosition = bHeadshot ? Signature->HeadPosition : Signature->ChestPosition;

  ACharacter* QuantumChar = GetQuantumCharacter();
  if(!QuantumChar) return TargetPosition;

  float BulletSpeed = 80000.0f;
  if(IWeaponSystemInterface* Weapon = GetActiveQuantumWeapon()) {
      BulletSpeed = Weapon->GetBulletSpeed();
  }

  float Distance = FVector::Dist(QuantumChar->GetActorLocation(), TargetPosition);
  float TimeToHit = Distance / BulletSpeed;

  FVector Velocity = Target->GetVelocity();
  FVector Acceleration = Target->GetCharacterMovement()->GetCurrentAcceleration();

  return TargetPosition + 
         (Velocity * TimeToHit) + 
         (0.5f * Acceleration * FMath::Square(TimeToHit)) +
         FVector(0, 0, -0.5f * 980.0f * FMath::Square(TimeToHit));
}

void UQuantumBallisticTracker::ActivateChaosEngine(FVector& Prediction) {
  float ChaosValue = FMath::PerlinNoise3D(
      FVector(ChronalAccumulator * 0.3f, 
              ChronalAccumulator * 0.5f, 
              ChronalAccumulator * 0.7f));

  Prediction += FVector(
      ChaosValue * 2.0f,
      ChaosValue * 1.5f,
      ChaosValue * 0.5f
  ) * BallisticProfile.ChaosFactor;
}

void UQuantumBallisticTracker::FoldSpaceTime(FVector& Prediction) {
  float FoldFactor = FMath::Sin(ChronalAccumulator * 2.0f) * 
                   FMath::Cos(ChronalAccumulator * 1.3f) * 
                   BallisticProfile.SpaceFoldIntensity;

  Prediction = Prediction.RotateAngleAxis(FoldFactor * 10.0f, FVector::UpVector);
}

void UQuantumBallisticTracker::ApplyQuantumTunneling(FVector& Prediction) {
  ACharacter* QuantumChar = GetQuantumCharacter();
  if(!QuantumChar) return;

  FVector ToTarget = (Prediction - QuantumChar->GetActorLocation()).GetSafeNormal();
  float TunnelEffect = FMath::PerlinNoise1D(ChronalAccumulator * 3.0f) * 
                      EntanglementData.TunnelingFactor;

  Prediction += ToTarget * TunnelEffect * 50.0f;
}

void UQuantumBallisticTracker::CalculateDarkMatterInfluence(FVector& Prediction) {
  if(ChronalAccumulator > 10.0f) {
      DarkMatterVector = DarkMatterVector.RotateAngleAxis(15.0f, FVector(
          FMath::FRandRange(-1.0f, 1.0f),
          FMath::FRandRange(-1.0f, 1.0f),
          FMath::FRandRange(-1.0f, 1.0f)
      ).GetSafeNormal());
      ChronalAccumulator = 0.0f;
  }

  Prediction += DarkMatterVector * BallisticProfile.DarkMatterInfluence;
}

void UQuantumBallisticTracker::ApplyStringTheoryCorrection(FVector& Prediction) {
    float StringTheoryOffset = FMath::Sin(ChronalAccumulator * 5.0f) * 
                             FMath::Cos(ChronalAccumulator * 3.7f) * 
                             BallisticProfile.StringTheoryFactor;
    
    Prediction += FVector(
        StringTheoryOffset * 1.2f,
        StringTheoryOffset * 0.8f,
        StringTheoryOffset * 0.3f
    );
}

void UQuantumBallisticTracker::ApplyEntanglementField(FVector& Prediction, ACharacter* Target) {
    if(!Target) return;
    
    float QuantumOffset = FMath::Sin(ChronalAccumulator * EntanglementData.EntanglementFrequency) * 
                         EntanglementData.EntanglementFactor;
    
    Prediction += FVector(
        QuantumOffset * 0.7f,
        QuantumOffset * 1.2f,
        QuantumOffset * 0.3f
    );
}

void UQuantumBallisticTracker::CalculateChronalDistortion(FVector& Prediction) {
    float TimeWarp = FMath::PerlinNoise1D(ChronalAccumulator * 0.7f) * 
                    BallisticProfile.ChronalDistortion;
    
    Prediction += FVector(TimeWarp, TimeWarp * 0.6f, TimeWarp * 0.2f);
}

void UQuantumBallisticTracker::ProcessNeuralPredictionMatrix(FVector& Prediction, ACharacter* Target) {
    if(!QuantumPredictionMatrix || !Target) return;
    
    TArray<float> Inputs;
    Inputs.Add(Target->GetVelocity().X);
    Inputs.Add(Target->GetVelocity().Y);
    Inputs.Add(Target->GetVelocity().Z);
    Inputs.Add(Target->GetCharacterMovement()->GetCurrentAcceleration().Size());
    Inputs.Add(FVector::Dist(GetQuantumCharacter()->GetActorLocation(), Target->GetActorLocation()));
    Inputs.Add(GetActiveQuantumWeapon() ? GetActiveQuantumWeapon()->GetBulletSpeed() : 80000.0f);
    Inputs.Add(ChronalAccumulator);
    Inputs.Add(DarkMatterVector.Size());
    
    TArray<float> Outputs = QuantumPredictionMatrix->Process(Inputs);
    
    if(Outputs.Num() >= 4) {
        Prediction += FVector(Outputs[0], Outputs[1], Outputs[2]) * Outputs[3];
    }
}

void UQuantumBallisticTracker::AdjustToQuantumEnvironment(FVector& Prediction) {
    ACharacter* QuantumChar = GetQuantumCharacter();
    if(!QuantumChar) return;
    
    float QuantumNoise = FMath::PerlinNoise3D(
        FVector(QuantumChar->GetActorLocation().X * 0.01f,
                QuantumChar->GetActorLocation().Y * 0.01f,
                ChronalAccumulator * 0.5f)) * 2.0f - 1.0f;
    
    Prediction += FVector(QuantumNoise, QuantumNoise * 0.8f, 0) * BallisticProfile.EnvironmentAdaptation;
}

void UQuantumBallisticTracker::GenerateHolographicVortex() {
    if(HolographicVortexPoints.Num() > 5) {
        HolographicVortexPoints.RemoveAt(0);
    }
    
    ACharacter* QuantumChar = GetQuantumCharacter();
    if(!QuantumChar) return;
    
    FVector NewVortexPoint = QuantumChar->GetActorLocation() + FVector(
        FMath::FRandRange(-200.0f, 200.0f),
        FMath::FRandRange(-200.0f, 200.0f),
        FMath::FRandRange(-80.0f, 80.0f)
    );
    
    HolographicVortexPoints.Add(NewVortexPoint);
}

void UQuantumBallisticTracker::UpdateQuantumTargetData() {
    TArray<AActor*> AllQuantumEntities;
    UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACharacter::StaticClass(), AllQuantumEntities);
    
    ACharacter* QuantumChar = GetQuantumCharacter();
    if(!QuantumChar) return;
    
    for(AActor* QuantumActor : AllQuantumEntities) {
        ACharacter* QuantumTarget = Cast<ACharacter>(QuantumActor);
        if(QuantumTarget && QuantumTarget != QuantumChar) {
            FQuantumTargetSignature Signature;
            
            const FVector HeadOffset = FVector(0, 0, QuantumTarget->GetCapsuleComponent()->GetScaledCapsuleHalfHeight());
            Signature.HeadPosition = QuantumTarget->GetActorLocation() + HeadOffset;
            Signature.ChestPosition = QuantumTarget->GetActorLocation() + HeadOffset * 0.7f;
            Signature.MovementPredictionFactor = QuantumTarget->GetVelocity().Size() / 1000.0f;
            Signature.QuantumSignature = FMath::FRand();
            Signature.LastUpdateTime = GetWorld()->GetTimeSeconds();
            
            QuantumTargets.Add(QuantumTarget, Signature);
        }
    }
}

void UQuantumBallisticTracker::ExecuteQuantumShot(ACharacter* Target, const FVector& PredictedPosition) {
    if(!Target) return;
    
    FHitResult HitResult;
    FCollisionQueryParams QueryParams;
    QueryParams.AddIgnoredActor(GetQuantumCharacter());
    
    GetWorld()->LineTraceSingleByChannel(
        HitResult,
        GetQuantumCharacter()->GetActorLocation(),
        PredictedPosition,
        ECC_Visibility,
        QueryParams
    );
    
    if(HitResult.GetActor() == Target) {
        Target->TakeDamage(100.0f * BallisticProfile.HeadshotMultiplier, 
                          FDamageEvent(), 
                          GetQuantumController(), 
                          GetQuantumCharacter());
    }
}

APlayerController* UQuantumBallisticTracker::GetQuantumController() const {
    return Cast<APlayerController>(GetOwner());
}

ACharacter* UQuantumBallisticTracker::GetQuantumCharacter() const {
    APlayerController* PC = GetQuantumController();
    return PC ? PC->GetCharacter() : nullptr;
}

IWeaponSystemInterface* UQuantumBallisticTracker::GetActiveQuantumWeapon() const {
    ACharacter* QuantumChar = GetQuantumCharacter();
    if(!QuantumChar) return nullptr;
    return Cast<IWeaponSystemInterface>(QuantumChar->FindComponentByClass(UWeaponSystemComponent::StaticClass()));
}