#include "QuantumBallisticLibrary.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"
#include "GameFramework/Character.h"
#include "DrawDebugHelpers.h"

FVector UQuantumBallisticLibrary::CalculateQuantumTrajectory(const FVector& Start, const FVector& Target, float BulletSpeed, float Gravity, float ChaosFactor) {
  FVector Direction = (Target - Start).GetSafeNormal();
  float Distance = FVector::Dist(Start, Target);
  float TimeToTarget = Distance / BulletSpeed;

  FVector ChaosVec = CalculateChaosVector(UKismetSystemLibrary::GetGameTimeInSeconds(nullptr), ChaosFactor);

  return Target + 
         FVector(0, 0, -0.5f * Gravity * FMath::Square(TimeToTarget)) + 
         ChaosVec * TimeToTarget;
}

FVector UQuantumBallisticLibrary::ApplyQuantumFluctuation(const FVector& Direction, float Intensity, float Time) {
  float NoiseX = FMath::PerlinNoise1D(Time * 0.7f);
  float NoiseY = FMath::PerlinNoise1D(Time * 0.7f + 100.0f);
  float NoiseZ = FMath::PerlinNoise1D(Time * 0.7f + 200.0f);

  return Direction + FVector(NoiseX, NoiseY, NoiseZ) * Intensity;
}

float UQuantumBallisticLibrary::CalculateQuantumThreatLevel(ACharacter* Target, ACharacter* Player, float ChronalTime) {
  if(!Target || !Player) return 0.0f;

  float Distance = FVector::Dist(Target->GetActorLocation(), Player->GetActorLocation());
  float VelocityFactor = Target->GetVelocity().Size() / 600.0f;
  float HealthFactor = 1.0f - (Target->GetHealth() / 100.0f);
  float TimeFactor = FMath::Sin(ChronalTime * 0.5f) * 0.5f + 0.5f;

  return (HealthFactor * 0.5f) + (VelocityFactor * 0.3f) + (TimeFactor * 0.2f);
}

FVector UQuantumBallisticLibrary::GetQuantumEnvironmentalInfluence(const FVector& Location, float Time, const FVector& DarkMatterVector) {
  float WindX = FMath::PerlinNoise2D(FVector2D(Location.X * 0.01f, Time * 0.3f));
  float WindY = FMath::PerlinNoise2D(FVector2D(Location.Y * 0.01f, Time * 0.3f + 100.0f));

  return FVector(WindX, WindY, 0) * 50.0f + DarkMatterVector * 30.0f;
}

void UQuantumBallisticLibrary::DrawQuantumDebugArc(UObject* WorldContext, const FVector& Start, const FVector& End, float BulletSpeed, float Gravity, float ChaosFactor) {
  const int32 NumSegments = 30;
  const float TimeTotal = FVector::Dist(Start, End) / BulletSpeed;

  FVector PreviousPoint = Start;
  for(int32 i = 1; i <= NumSegments; i++) {
      float SegmentTime = TimeTotal * (float)i / (float)NumSegments;
      FVector SegmentPosition = FMath::Lerp(Start, End, (float)i / (float)NumSegments);

      FVector ChaosOffset = CalculateChaosVector(SegmentTime, ChaosFactor);

      SegmentPosition += 
          FVector(0, 0, -0.5f * Gravity * FMath::Square(SegmentTime)) + 
          ChaosOffset * SegmentTime;

      DrawDebugLine(
          WorldContext->GetWorld(),
          PreviousPoint,
          SegmentPosition,
          FColor::Emerald,
          false, -1.0f, 0,
          3.0f
      );

      PreviousPoint = SegmentPosition;
  }
}

FVector UQuantumBallisticLibrary::CalculateChaosVector(float Time, float ChaosFactor) {
  return FVector(
      FMath::PerlinNoise1D(Time * 1.1f) * ChaosFactor,
      FMath::PerlinNoise1D(Time * 1.3f + 50.0f) * ChaosFactor,
      FMath::PerlinNoise1D(Time * 0.9f + 100.0f) * ChaosFactor * 0.5f
  );
}

FVector UQuantumBallisticLibrary::FoldSpaceTimeVector(const FVector& Input, float Time, float Intensity) {
  float FoldX = FMath::Sin(Time * 2.0f) * Intensity;
  float FoldY = FMath::Cos(Time * 1.5f) * Intensity;

  return FVector(
      Input.X * (1.0f + FoldX),
      Input.Y * (1.0f + FoldY),
      Input.Z
  );
}

float UQuantumBallisticLibrary::CalculateTunnelingProbability(float Distance, float Time) {
  return FMath::Clamp(
      (FMath::Sin(Distance * 0.001f + Time * 2.0f) * 0.5f + 0.5f) * 
      FMath::Exp(-Distance / 50000.0f),
      0.0f, 1.0f
  );
}

FVector UQuantumBallisticLibrary::ApplyDarkMatterEffect(const FVector& Input, const FVector& DarkMatterVector, float Influence) {
  return Input + DarkMatterVector * Influence * Input.Size() / 1000.0f;
}

FVector UQuantumBallisticLibrary::CalculateStringTheoryOffset(float Time, float Factor) {
  return FVector(
      FMath::Sin(Time * 5.0f) * Factor,
      FMath::Cos(Time * 3.7f) * Factor * 0.8f,
      FMath::Sin(Time * 4.2f) * Factor * 0.3f
  );
}