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

#pragma once

#include "AudioCaptureCore.h"
#include "AudioDevice.h"
#include "Containers/ContainerAllocationPolicies.h"
#include "Containers/Queue.h"
#include "CoreMinimal.h"
#include "Graph/InworldData.h"
#include "InworldRuntimeTypes.h"
#include "Primitives/AEC/InworldAECTypes.h"
#include "Primitives/VAD/InworldVADTypes.h"
#include "Templates/PimplPtr.h"
#include "UObject/NoExportTypes.h"

#include "InworldAudioCapture.generated.h"

namespace inworld
{
class VADInterface;
class AECFilterInterface;
}	 // namespace inworld

/**
 * @struct FInworldAudioCaptureData
 * @brief Data structure containing captured audio information.
 *
 * This structure encapsulates audio data captured from input devices,
 * including the raw audio samples and their format specifications.
 */
struct FInworldAudioCaptureData
{
	/** Array of audio samples as floating-point values (-1.0 to 1.0) */
	TArray<float> AudioData;

	/** Number of audio channels in the captured data */
	int32 NumChannels;

	/** Sample rate of the captured audio in Hz */
	int32 SampleRate;
};

/**
 * @struct FInworldAudioCapture
 * @brief Abstract base interface for audio capture implementations.
 *
 * This structure provides a platform-agnostic interface for audio capture
 * functionality, allowing different implementations for various audio backends
 * while maintaining a consistent API for audio recording operations.
 */
struct FInworldAudioCapture
{
public:
	/**
	 * @brief Constructor for the audio capture interface.
	 *
	 * @param InOwner Weak reference to the owning object for lifecycle management
	 * @param InCallback Callback function to receive captured audio data
	 */
	FInworldAudioCapture(TWeakObjectPtr<UObject> InOwner, TFunction<void(FInworldAudioCaptureData)> InCallback)
		: Owner(InOwner), AudioDataCallback(InCallback)
	{
	}

	/**
	 * @brief Virtual destructor for proper cleanup of derived implementations.
	 */
	virtual ~FInworldAudioCapture() = default;

	/**
	 * @brief Starts the audio capture process.
	 *
	 * This pure virtual function must be implemented by derived classes to begin
	 * recording audio from the selected input device.
	 */
	virtual void StartCapture() = 0;

	/**
	 * @brief Stops the audio capture process.
	 *
	 * This pure virtual function must be implemented by derived classes to halt
	 * audio recording and cleanup any associated resources.
	 */
	virtual void StopCapture() = 0;

	/**
	 * @brief Sets the audio capture device by its identifier.
	 *
	 * This pure virtual function allows switching between different audio input
	 * devices during runtime by specifying the device's unique identifier.
	 *
	 * @param DeviceId Unique identifier of the audio capture device to use
	 */
	virtual void SetCaptureDeviceById(const FString& DeviceId) = 0;

protected:
	/** Weak reference to the owning object for lifecycle management */
	TWeakObjectPtr<UObject> Owner;

	/** Callback function invoked when audio data is captured */
	TFunction<void(FInworldAudioCaptureData)> AudioDataCallback;
};

/** Blueprint delegate called when audio capture instance creation is completed */
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInworldAudioCaptureCreated, UInworldAudioCapture*, InworldAudioCapture);

/** Native delegate called when audio capture instance creation is completed */
DECLARE_DELEGATE_OneParam(FOnInworldAudioCaptureCreatedNative, UInworldAudioCapture* /*InworldAudioCapture*/);

/** Blueprint delegate called when audio data is captured with VAD (Voice Activity Detection) results */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
	FOnInworldAudioCapture, const UInworldAudioCapture*, AudioCapture, const FInworldData_Audio&, Audio, bool, bVAD);

/** Native delegate called when audio data is captured with VAD (Voice Activity Detection) results */
DECLARE_MULTICAST_DELEGATE_ThreeParams(
	FOnInworldAudioCaptureNative, const UInworldAudioCapture* /*AudioCapture*/, const FInworldData_Audio& /*Audio*/, bool /*bVAD*/);

/**
 * @struct FInworldAudioCaptureConfig
 * @brief Configuration structure for audio capture settings and processing options.
 *
 * This structure defines the parameters for audio capture operations, including
 * capture rate, AEC (Acoustic Echo Cancellation), and VAD (Voice Activity Detection)
 * configurations for optimal audio processing and transmission.
 */
USTRUCT(BlueprintType)
struct FInworldAudioCaptureConfig
{
	GENERATED_BODY()

public:
	/** The frequency at which audio is captured (measured in cycles per second). Controls how frequently OnAudioCapture is
	 * fired. E.g. If CaptureFrequency = 10, OnAudioCapture will be called 10 times per second.*/
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Audio",
		meta = (Units = "Hz",
			Tooltip =
				"The frequency at which audio is captured (measured in cycles per second). Controls how frequently OnAudioCapture is fired. E.g. If CaptureFrequency = 10, OnAudioCapture will be called 10 times per second."))
	int32 CaptureFrequency{10};

	/** Whether to enable Acoustic Echo Cancellation (AEC) processing */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|AEC",
		meta = (Tooltip =
					"Whether to enable Acoustic Echo Cancellation (AEC) processing to reduce feedback and echoes from audio output."))
	bool bEnableAEC{true};

	/** Configuration settings for AEC processing when enabled */
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Inworld|AEC",
		Meta = (EditCondition = bEnableAEC, EditConditionHides,
			Tooltip = "Configuration settings for Acoustic Echo Cancellation (AEC) processing."))
	FInworldAECConfig AECConfig{};

public:
	/** Whether to enable Voice Activity Detection (VAD) processing */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|AEC",
		meta = (Tooltip = "Whether to enable Voice Activity Detection (VAD) to detect when speech is present in the audio input."))
	bool bEnableVAD{true};

	/** Configuration settings for VAD processing when enabled */
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Inworld|VAD",
		Meta = (EditCondition = bEnableVAD, EditConditionHides,
			Tooltip = "Configuration settings for Voice Activity Detection (VAD) processing."))
	FInworldVADConfig VADConfig{};
};

/**
 * @class UInworldAudioCapture
 * @brief High-level audio capture system with advanced processing capabilities.
 *
 * This class provides comprehensive audio capture functionality with integrated
 * AEC (Acoustic Echo Cancellation) and VAD (Voice Activity Detection) processing.
 * It manages both input and output audio streams, applies real-time filtering,
 * and provides event-driven notifications for captured audio data.
 *
 * Key features:
 * - Dual audio stream capture (input and output for AEC)
 * - Real-time AEC and VAD processing
 * - Configurable capture rates and processing settings
 * - Thread-safe audio buffer management
 * - Event-driven architecture with capture notifications
 * - Asynchronous processing pipeline for optimal performance
 */
UCLASS(ClassGroup = (Inworld), NotBlueprintable, BlueprintType)
class INWORLDRUNTIME_API UInworldAudioCapture final : public UObject
{
	GENERATED_BODY()

public:
	/** Creates an instance of UInworldAudioCapture for capturing audio input.
	 *
	 * This function initializes a new audio capture object, wich can be used to start/stop audio recording.
	 *
	 * @return A pointer to the newly created UInworldAudioCapture instance.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Factory", meta = (WorldContext = "WorldContextObject"))
	static void CreateInworldAudioCapture(
		UObject* WorldContextObject, const FInworldAudioCaptureConfig& Config, FOnInworldAudioCaptureCreated Callback);
	static void CreateInworldAudioCapture(UObject* WorldContextObject = nullptr, const FInworldAudioCaptureConfig& Config = {},
		FOnInworldAudioCaptureCreatedNative Callback = {});

	virtual void PostInitProperties() override;
	virtual void BeginDestroy() override;

	/** Starts capturing audio from the selected input device.
	 *
	 * This function begins recording audio data from the active capture device.
	 * The captured audio is processed and can be retrived using OnAudioCapture event callbacks.
	 *
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Audio")
	void StartCapture();

	/** Stops capturing audio.
	 *
	 * This function halts the audio capture process and ensures that no further data is recorded.
	 * Any buffered audio data is discarded, and no more events will be brodcasted.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Audio")
	void StopCapture();

	/** The frequency at which audio is captured (measured in cycles per second). Controls how frequently OnAudioCapture is
	 * fired. E.g. If CaptureFrequency = 10, OnAudioCapture will be called 10 times per second.*/
	UPROPERTY(BlueprintReadOnly, Category = "Inworld|Audio",
		meta = (Units = "Hz",
			Tooltip =
				"The frequency at which audio is captured (measured in cycles per second). Controls how frequently OnAudioCapture is fired. E.g. If CaptureFrequency = 10, OnAudioCapture will be called 10 times per second."))
	int32 CaptureFrequency{10};

	/** Whether Acoustic Echo Cancellation (AEC) is currently enabled */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|AEC",
		meta = (Tooltip =
					"Whether Acoustic Echo Cancellation (AEC) is currently enabled to reduce feedback and echoes from audio output."))
	bool bUseAEC{};

	/** Runtime configuration settings for AEC processing */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|AEC",
		meta = (Tooltip = "Runtime configuration settings for Acoustic Echo Cancellation (AEC) processing."))
	FInworldAECConfig AECConfig{};

	/** Whether Voice Activity Detection (VAD) is currently enabled */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|VAD",
		meta = (Tooltip =
					"Whether Voice Activity Detection (VAD) is currently enabled to detect when speech is present in the audio input."))
	bool bUseVAD{};

	/** Runtime configuration settings for VAD processing */
	UPROPERTY(BlueprintReadWrite, Category = "Inworld|VAD",
		meta = (Tooltip = "Runtime configuration settings for Voice Activity Detection (VAD) processing."))
	FInworldVADConfig VADConfig{};

	/** Blueprint delegate called when audio is captured with processing results */
	UPROPERTY(BlueprintAssignable, Category = "Inworld|Audio",
		meta = (Tooltip =
					"Event called when audio is captured with processing results. Includes the captured audio data and Voice Activity Detection (VAD) result."))
	FOnInworldAudioCapture OnAudioCapture;

	/** Native delegate called when audio is captured with processing results */
	FOnInworldAudioCaptureNative OnAudioCaptureNative;

protected:
	/**
	 * @brief Attempts to process accumulated audio data through the AEC and VAD pipeline.
	 *
	 * This function is called periodically to process buffered audio data, applying
	 * AEC filtering and VAD detection before notifying listeners of processed results.
	 */
	void TryProcessAudio();

	/** Thread-safe interface for input audio capture operations */
	TSharedPtr<FInworldAudioCapture, ESPMode::ThreadSafe> InputAudioCapture;

	/** Thread-safe interface for output audio capture operations (used for AEC reference) */
	TSharedPtr<FInworldAudioCapture, ESPMode::ThreadSafe> OutputAudioCapture;

	/**
	 * @struct FAudioBuffer
	 * @brief Thread-safe audio buffer for storing captured audio data.
	 *
	 * This structure provides thread-safe storage for audio samples with
	 * proper alignment for SIMD operations and sample rate tracking.
	 */
	struct FAudioBuffer
	{
		/** Thread-safe access to audio buffer data */
		TQueue<TArray<float>> PCQueue;

		/** Audio sample data with 16-byte alignment for optimal SIMD performance */
		TArray<float, TAlignedHeapAllocator<16>> Data;

		/** Sample rate of the audio data stored in this buffer */
		int32 SampleRate;
	};

	/** Buffer for storing captured input audio data */
	FAudioBuffer InputBuffer;

	/** Buffer for storing captured output audio data (for AEC reference) */
	FAudioBuffer OutputBuffer;

	/** Atomic flag indicating whether audio capture is currently active */
	TAtomic<bool> bCapturingAudio = false;

	/** Critical section for synchronizing audio processing operations */
	FCriticalSection ProcessAudioCriticalSection;

	/** Asynchronous task handle for audio processing operations */
	UE::Tasks::TTask<void> ProcessAudioTask;

	/** Internal index for tracking audio capture state and processing */
	int32 Index{INDEX_NONE};

private:
#if WITH_EDITOR && !UE_BUILD_SHIPPING
	/** Whether to enable debug audio dumping for development and testing */
	bool bDebugDumpAudio{false};

	/** File path for dumping captured input audio data for debugging */
	FString DebugDumpInputAudioFile{};

	/** File path for dumping captured output audio data for debugging */
	FString DebugDumpOutputAudioFile{};

	/** File path for dumping processed result audio data for debugging */
	FString DebugDumpResultAudioFile{};
#endif
};
