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

#pragma once

#include "Components/AudioComponent.h"
#include "CoreMinimal.h"
#include "Graph/InworldData.h"
#include "InworldRuntimeTypes.h"

#include "InworldVoiceAudioComponent.generated.h"

/** Blueprint delegate called when voice audio playback starts */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
	FOnInworldVoiceAudioStart, UInworldVoiceAudioComponent*, VoiceAudioComponent, const FInworldData_TTSOutput&, Voice);

/** Blueprint delegate called during voice audio playback with timing information */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnVoiceAudioPlayback, UInworldVoiceAudioComponent*, VoiceAudioComponent,
	const float, PlaybackDuration, const float, PlaybackTimeSeconds);

/** Blueprint delegate called when voice audio playback completes normally */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
	FOnInworldVoiceAudioComplete, UInworldVoiceAudioComponent*, VoiceAudioComponent, const FInworldData_TTSOutput&, Voice);

/** Blueprint delegate called when voice audio playback is interrupted */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
	FOnInworldVoiceAudioInterrupt, UInworldVoiceAudioComponent*, VoiceAudioComponent, const FInworldData_TTSOutput&, Voice);

/** Native delegate called when voice audio playback starts */
DECLARE_MULTICAST_DELEGATE_TwoParams(
	FOnInworldVoiceAudioStartNative, UInworldVoiceAudioComponent* /*VoiceAudioComponent*/, const FInworldData_TTSOutput& /*Voice*/);

/** Native delegate called during voice audio playback with timing information */
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnVoiceAudioPlaybackNative, UInworldVoiceAudioComponent* /*VoiceAudioComponent*/,
	const float /*PlaybackDuration*/, const float /*PlaybackTimeSeconds*/);

/** Native delegate called when voice audio playback completes normally */
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnInworldVoiceAudioCompleteNative, UInworldVoiceAudioComponent* /*VoiceAudioComponent*/,
	const FInworldData_TTSOutput& /*Voice*/);

/** Native delegate called when voice audio playback is interrupted */
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnInworldVoiceAudioInterruptNative, UInworldVoiceAudioComponent* /*VoiceAudioComponent*/,
	const FInworldData_TTSOutput& /*Voice*/);

/** Native delegate called when signed audio data is generated for lip-sync processing */
DECLARE_DELEGATE_TwoParams(FOnSignedAudioDataGenerated, TArray<int16>&& /*AudioData*/, const int32 /*SampleRate*/);

/**
 * @class UInworldVoiceAudioComponent
 * @brief Specialized audio component for TTS voice playback with advanced features.
 *
 * This component extends UAudioComponent to provide specialized functionality for
 * playing synthesized voice audio from the Inworld TTS system. It manages voice
 * queuing, playback interruption, and playback timing events.
 *
 * Key features:
 * - Queue-based voice playback management
 * - Playback interruption and cleanup
 * - Real-time playback timing events
 * - Thread-safe voice queue operations
 * - Event-driven architecture for playback notifications
 */
UCLASS(ClassGroup = (Inworld), meta = (BlueprintSpawnableComponent))
class INWORLDRUNTIME_API UInworldVoiceAudioComponent : public UAudioComponent
{
	GENERATED_BODY()

public:
	/** Blueprint delegate called when voice audio playback begins */
	UPROPERTY(BlueprintAssignable)
	FOnInworldVoiceAudioStart OnVoiceAudioStart;

	/** Native delegate called when voice audio playback begins */
	FOnInworldVoiceAudioStartNative OnVoiceAudioStartNative;

	/** Blueprint delegate called during voice audio playback with timing updates */
	UPROPERTY(BlueprintAssignable)
	FOnVoiceAudioPlayback OnVoiceAudioPlayback;

	/** Native delegate called during voice audio playback with timing updates */
	FOnVoiceAudioPlaybackNative OnVoiceAudioPlaybackNative;

	/** Blueprint delegate called when voice audio playback completes normally */
	UPROPERTY(BlueprintAssignable)
	FOnInworldVoiceAudioComplete OnVoiceAudioComplete;

	/** Native delegate called when voice audio playback completes normally */
	FOnInworldVoiceAudioCompleteNative OnVoiceAudioCompleteNative;

	/** Blueprint delegate called when voice audio playback is interrupted */
	UPROPERTY(BlueprintAssignable)
	FOnInworldVoiceAudioInterrupt OnVoiceAudioInterrupt;

	/** Native delegate called when voice audio playback is interrupted */
	FOnInworldVoiceAudioInterruptNative OnVoiceAudioInterruptNative;

	/** Native delegate called when audio data is generated for lip-sync animation */
	FOnSignedAudioDataGenerated OnSignedAudioDataGenerated;

	/**
	 * @brief Called when the component begins play.
	 *
	 * This override initializes the voice audio system and sets up the
	 * procedural sound wave for streaming audio playback.
	 */
	virtual void BeginPlay() override;

	/**
	 * @brief Called when the component ends play.
	 *
	 * This override performs cleanup of the voice audio system and ensures
	 * proper resource management when the component is destroyed or the
	 * game ends.
	 *
	 * @param Reason The reason why EndPlay is being called
	 */
	virtual void EndPlay(EEndPlayReason::Type Reason) override;

	/** Queues a voice chunk for playback.
	 *
	 * This function adds the provided voice data to the playback queue.
	 * If this is the first chunk in the queue, it sets the sample rate and channel configuration
	 * based on the incoming audio data.
	 *
	 * Events: OnVoiceAudioStart, OnVoiceAudioComplete
	 *
	 * @param Voice The voice data to queue for playback.
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Audio")
	void QueueVoice(const FInworldData_TTSOutput& Voice);

	/** Interrupts the current voice playback.
	 *
	 * This function stops all pending voice chunks and immediately halts playback.
	 * It broadcasts an event to notify that the voice has been interrupted.
	 *
	 * Events: OnVoiceAudioInterrupt
	 */
	UFUNCTION(BlueprintCallable, Category = "Inworld|Audio")
	void Interrupt();

protected:
	/** Thread-safe lock for protecting access to the voice queue */
	mutable FCriticalSection QueueLock;

	/** Queue of voice outputs waiting to be played */
	TArray<FInworldData_TTSOutput> Voices{};

	/** Number of sound data bytes that have been played so far */
	int32 NumSoundDataBytesPlayed{0};

	/** Atomic flag indicating whether the component is awaiting cleanup */
	TAtomic<bool> bAwaitingCleanup = false;

	/** Sample rate of the source audio data */
	int32 SourceSampleRate{0};

	/**
	 * @brief Generates audio data for the procedural sound wave.
	 *
	 * This function is called by the audio system to generate the next batch
	 * of audio samples from the queued voice data. It handles sample rate
	 * conversion and provides audio data for lip-sync processing.
	 *
	 * @param InProceduralWave The procedural sound wave requesting audio data
	 * @param SamplesRequired The number of audio samples needed
	 */
	void GenerateData(class USoundWaveProcedural* InProceduralWave, int32 SamplesRequired);

	/** The procedural sound wave used for streaming audio playback */
	UPROPERTY(transient, Meta = (ToolTip = "The procedural sound wave used for streaming audio playback"))
	class USoundWaveProcedural* SoundStreaming{nullptr};
};
