// Copyright Pacificao. All Rights Reserved.

#include "AgrarianWeatherAudioController.h"

#include "AgrarianGameState.h"
#include "AgrarianPerformanceStats.h"
#include "Components/AudioComponent.h"
#include "Components/SceneComponent.h"
#include "Engine/World.h"
#include "ProfilingDebugging/CpuProfilerTrace.h"

AAgrarianWeatherAudioController::AAgrarianWeatherAudioController()
{
	PrimaryActorTick.bCanEverTick = true;
	bReplicates = false;

	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
	RootComponent = SceneRoot;

	AmbientAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("AmbientAudio"));
	AmbientAudio->SetupAttachment(SceneRoot);
	AmbientAudio->bAutoActivate = false;

	RainAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("RainAudio"));
	RainAudio->SetupAttachment(SceneRoot);
	RainAudio->bAutoActivate = false;

	WindAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("WindAudio"));
	WindAudio->SetupAttachment(SceneRoot);
	WindAudio->bAutoActivate = false;

	StormAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("StormAudio"));
	StormAudio->SetupAttachment(SceneRoot);
	StormAudio->bAutoActivate = false;
}

void AAgrarianWeatherAudioController::BeginPlay()
{
	Super::BeginPlay();
	AssignConfiguredSounds();
	RefreshWeatherAudio(0.0f);
}

void AAgrarianWeatherAudioController::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);
	RefreshWeatherAudio(DeltaSeconds);
}

void AAgrarianWeatherAudioController::RefreshWeatherAudio(float DeltaSeconds)
{
	SCOPE_CYCLE_COUNTER(STAT_AgrarianWeatherAudioRefresh);
	TRACE_CPUPROFILER_EVENT_SCOPE(AgrarianWeatherAudioRefresh);

	const UWorld* World = GetWorld();
	const AAgrarianGameState* GameState = World ? World->GetGameState<AAgrarianGameState>() : nullptr;
	if (!GameState)
	{
		return;
	}

	CurrentWeather = GameState->Weather;
	const float WindAlpha = GetProviderWindAlpha(GameState->ActiveWeatherInputs.WindSpeedKmh, GameState->ActiveWeatherInputs.bHasProviderData);
	float TargetRainVolume = 0.0f;
	float TargetWindVolume = WindAlpha * MaxWindVolume;
	float TargetStormVolume = 0.0f;

	switch (GameState->Weather)
	{
	case EAgrarianWeatherType::Rain:
		TargetRainVolume = MaxRainVolume;
		TargetWindVolume = FMath::Max(TargetWindVolume, MaxWindVolume * 0.25f);
		break;
	case EAgrarianWeatherType::ColdWind:
		TargetWindVolume = FMath::Max(TargetWindVolume, MaxWindVolume * 0.7f);
		break;
	case EAgrarianWeatherType::Storm:
		TargetRainVolume = MaxRainVolume;
		TargetWindVolume = MaxWindVolume;
		TargetStormVolume = MaxStormVolume;
		break;
	default:
		break;
	}

	const float TargetAmbientVolume = GameState->IsNight() ? AmbientNightVolume : AmbientDayVolume;
	const float InterpSpeed = FMath::Max(0.1f, VolumeInterpSpeed);
	CurrentAmbientVolume = FMath::FInterpTo(CurrentAmbientVolume, TargetAmbientVolume, DeltaSeconds, InterpSpeed);
	CurrentRainVolume = FMath::FInterpTo(CurrentRainVolume, TargetRainVolume, DeltaSeconds, InterpSpeed);
	CurrentWindVolume = FMath::FInterpTo(CurrentWindVolume, TargetWindVolume, DeltaSeconds, InterpSpeed);
	CurrentStormVolume = FMath::FInterpTo(CurrentStormVolume, TargetStormVolume, DeltaSeconds, InterpSpeed);

	if (DeltaSeconds <= 0.0f)
	{
		CurrentAmbientVolume = TargetAmbientVolume;
		CurrentRainVolume = TargetRainVolume;
		CurrentWindVolume = TargetWindVolume;
		CurrentStormVolume = TargetStormVolume;
	}

	ApplyComponentVolume(AmbientAudio, CurrentAmbientVolume);
	ApplyComponentVolume(RainAudio, CurrentRainVolume);
	ApplyComponentVolume(WindAudio, CurrentWindVolume);
	ApplyComponentVolume(StormAudio, CurrentStormVolume);
}

void AAgrarianWeatherAudioController::AssignConfiguredSounds()
{
	if (AmbientAudio && ClearAmbientSound)
	{
		AmbientAudio->SetSound(ClearAmbientSound);
	}
	if (RainAudio && RainLoopSound)
	{
		RainAudio->SetSound(RainLoopSound);
	}
	if (WindAudio && WindLoopSound)
	{
		WindAudio->SetSound(WindLoopSound);
	}
	if (StormAudio && StormLoopSound)
	{
		StormAudio->SetSound(StormLoopSound);
	}
}

void AAgrarianWeatherAudioController::ApplyComponentVolume(UAudioComponent* AudioComponent, float Volume) const
{
	if (!AudioComponent)
	{
		return;
	}

	const float SafeVolume = FMath::Clamp(Volume, 0.0f, 1.0f);
	AudioComponent->SetVolumeMultiplier(SafeVolume);
	if (AudioComponent->Sound && SafeVolume > 0.01f && !AudioComponent->IsPlaying())
	{
		AudioComponent->Play();
	}
	else if (SafeVolume <= 0.01f && AudioComponent->IsPlaying())
	{
		AudioComponent->Stop();
	}
}

float AAgrarianWeatherAudioController::GetProviderWindAlpha(float WindSpeedKmh, bool bHasProviderData) const
{
	if (!bHasProviderData)
	{
		return 0.0f;
	}

	return FMath::Clamp(WindSpeedKmh / 55.0f, 0.0f, 1.0f);
}
