/**
 * Copyright 2022-2025 Theai, Inc. dba Inworld AI
 */

#include "Audio/InworldAudioDumpUtils.h"

#include "GenericPlatform/GenericPlatformFile.h"
#include "HAL/PlatformFileManager.h"

#if WITH_EDITOR && !UE_BUILD_SHIPPING
namespace inworld
{

namespace audio
{

namespace debug
{

static TAutoConsoleVariable<bool> CVarInworldAudio_DebugDump(
	TEXT("inworld.audio.dump"), false, TEXT("Controls if Debug Audio is dumped.\n"), ECVF_Cheat);

const TAutoConsoleVariable<bool>& GetCVarDebugDump()
{
	return CVarInworldAudio_DebugDump;
}

static TAutoConsoleVariable<FString> CVarInworldAudio_DebugDumpPath(TEXT("inworld.audio.dumppath"),
	FPaths::ConvertRelativePathToFull(FPaths::ProjectLogDir()), TEXT("Controls where Debug Audio is dumped.\n"), ECVF_Cheat);

const TAutoConsoleVariable<FString>& GetCVarDebugDumpPath()
{
	return CVarInworldAudio_DebugDumpPath;
}

void DumpAudio(const FString& OutFileName, const FInworldData_Audio& Audio)
{
	IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();

	bool bFileExists = PlatformFile.FileExists(*OutFileName);
	if (IFileHandle* WavFile = PlatformFile.OpenWrite(*OutFileName, true); WavFile != nullptr)
	{
		if (!bFileExists)
		{
			const int16 NumChannels{1};
			const TArray<uint8> NumChannelsBits((uint8*) &NumChannels, 2);
			const TArray<uint8> SampleRateBits((uint8*) &Audio.SampleRate, 4);
			const TArray<uint8> WAVHeader	 // Binary Header
				{
					'R', 'I', 'F', 'F',	   // RIFF chunk
					0, 0, 0, 0,			   // Chunk 1 Size
					'W', 'A', 'V', 'E',	   // WAVE chunk
					'f', 'm', 't', ' ',	   // fmt chunk
					16, 0, 0, 0,		   // Length of format data
					1, 0,				   // Format type (PCM)
					NumChannelsBits[0],	   // Number of Channels
					NumChannelsBits[1],	   // Number of Channels
					SampleRateBits[0],	   // Sample Rate
					SampleRateBits[1],	   // Sample Rate
					SampleRateBits[2],	   // Sample Rate
					SampleRateBits[3],	   // Sample Rate
					0, 125, 0, 0,		   // Byte Rate (32000)?
					2, 0,				   // Block align
					16, 0,				   // Bits per sample (16)
					'd', 'a', 't', 'a',	   // data chunk
					0, 0, 0, 0			   // Chunk 2 size
				};
			WavFile->Write(WAVHeader.GetData(), WAVHeader.Num());
		}

		// Convert data to PCM
		TArray<int16> PCMData;
		TArray<float> AudioDataFloat{(float*) Audio.Waveform->GetData(), Audio.Waveform->Num() / 4};
		PCMData.Reserve(AudioDataFloat.Num());
		for (const float Sample : AudioDataFloat)
		{
			PCMData.Add(static_cast<int16>(Sample * 32767.0f));
		}

		// Append new data to wav file
		WavFile->Write((uint8*) PCMData.GetData(), PCMData.Num() * 2);

		// Update WAV header with size info
		const int32 FileSize = WavFile->Size() - 8;
		WavFile->Seek(4);
		WavFile->Write((uint8*) &FileSize, sizeof(FileSize));

		const int32 DataSize = WavFile->Size() - 44;
		WavFile->Seek(40);
		WavFile->Write((uint8*) &DataSize, sizeof(DataSize));

		delete WavFile;
	}
}

}	 // namespace debug
}	 // namespace audio
}	 // namespace inworld

#endif
