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

#pragma once

#include "InworldRuntimeTypes.h"
#include "Logging/LogMacros.h"

namespace inworld
{
class TTSInterface;
}

#include "InworldTTSTypes.generated.h"

INWORLDRUNTIME_API DECLARE_LOG_CATEGORY_EXTERN(LogInworldTTS, Log, All);

/**
 * @struct FInworldSpeechSynthesisPostprocessingConfig
 * @brief Configuration for post-processing speech synthesis output.
 *
 * This structure defines audio processing parameters applied after speech synthesis,
 * including output sample rate specifications.
 */
USTRUCT(BlueprintType)
struct FInworldSpeechSynthesisPostprocessingConfig
{
	GENERATED_BODY()

	/** The sample rate for the output waveform. */
	UPROPERTY(EditDefaultsOnly, Category = "Inworld|TTS",
		Meta = (ToolTip = "The sample rate for the output waveform in Hz (default: 24000)"))
	int32 SampleRate{24000};
};

/**
 * @struct FInworldSpeechSynthesisInferenceConfig
 * @brief Configuration for TTS model inference parameters.
 *
 * This structure defines the inference-time parameters that control the behavior
 * of the TTS model during speech generation, including creativity and speaking rate.
 */
USTRUCT(BlueprintType)
struct FInworldSpeechSynthesisInferenceConfig
{
	GENERATED_BODY()

	/** If the temperature should be overridden from the internal default. */
	UPROPERTY(EditDefaultsOnly, Category = "Inworld|TTS",
		Meta = (ToolTip = "If the temperature should be overridden from the internal default."))
	bool bOverrideTemperature{false};
	/** The temperature of the model. Range (0, 2]. Higher temperature means more
	 * creative output. */
	UPROPERTY(EditDefaultsOnly, Category = "Inworld|TTS",
		Meta = (EditCondition = "bOverrideTemperature", EditConditionHides,
			ToolTip = "The temperature of the model. Range (0, 2]. Higher temperature means more creative output."))
	float Temperature{1.0f};
	/** Speaking rate/speed, in the range [0.5, 1.5]. Default: 1.0. */
	UPROPERTY(
		EditDefaultsOnly, Category = "Inworld|TTS", Meta = (ToolTip = "Speaking rate/speed, in the range [0.5, 1.5]. Default: 1.0"))
	float SpeakingRate{1.f};
};

/**
 * @struct FInworldTTSSpeechSynthesisConfig
 * @brief Configuration for Inworld TTS synthesis operations.
 *
 * This structure combines model selection, post-processing, and inference configurations
 * for comprehensive control over Inworld's text-to-speech synthesis process.
 */
USTRUCT(BlueprintType, Blueprintable)
struct FInworldTTSSpeechSynthesisConfig
{
	GENERATED_BODY()

	/** The model version for speech generation. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS", config,
		Meta = (GetOptions = "InworldRuntimeSettings.GetRemoteTTSModels", NoResetToDefault,
			ToolTip = "The model version for speech generation"))
	FString ModelId{"inworld-tts-1"};

	/** Post-processing configuration for output audio */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS", config,
		Meta = (ToolTip = "Post-processing configuration for output audio"))
	FInworldSpeechSynthesisPostprocessingConfig SpeechSynthesisPostprocessingConfig;

	/** Inference configuration for model behavior */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS", config,
		Meta = (ToolTip = "Inference configuration for model behavior"))
	FInworldSpeechSynthesisInferenceConfig SpeechSynthesisInferenceConfig;
};

/**
 * @enum EElevenLabsTTSTextNormalization
 * @brief Enumeration for ElevenLabs TTS text normalization options.
 */
UENUM(BlueprintType)
enum class EElevenLabsTTSTextNormalization : uint8
{
	/** Automatic text normalization based on content */
	AUTO UMETA(DisplayName = "Auto"),
	/** Force text normalization on */
	ON UMETA(DisplayName = "On"),
	/** Disable text normalization */
	OFF UMETA(DisplayName = "Off"),
};

/**
 * @enum EElevenLabsTTSOutputFormat
 * @brief Enumeration for ElevenLabs TTS output audio format options.
 */
UENUM(BlueprintType)
enum class EElevenLabsTTSOutputFormat : uint8
{
	/** MP3 format at 22050Hz sample rate with 32kbps bitrate */
	MP3_22050_32 UMETA(DisplayName = "MP3 22050Hz 32kbps"),
	// TODO: Support additional output format options
	// MP3_44100_32 UMETA(DisplayName = "MP3 44100Hz 32kbps"),
	// MP3_44100_64 UMETA(DisplayName = "MP3 44100Hz 64kbps"),
	// MP3_44100_96 UMETA(DisplayName = "MP3 44100Hz 96kbps"),
	// MP3_44100_128 UMETA(DisplayName = "MP3 44100Hz 128kbps"),
	// MP3_44100_192 UMETA(DisplayName = "MP3 44100Hz 192kbps"),
};

/**
 * @struct FElevenLabsTTSSpeechSynthesisConfig
 * @brief Configuration for ElevenLabs TTS synthesis operations.
 *
 * This structure defines the parameters specific to ElevenLabs TTS service,
 * including logging, output format, model selection, and text processing options.
 */
USTRUCT(BlueprintType, Blueprintable)
struct FElevenLabsTTSSpeechSynthesisConfig
{
	GENERATED_BODY()

public:
	/** Whether to enable detailed logging for ElevenLabs API calls */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS|Query",
		Meta = (ToolTip = "Whether to enable detailed logging for ElevenLabs API calls"))
	bool EnableLogging{false};

	/** The audio output format for the synthesized speech */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS|Query",
		Meta = (ToolTip = "The audio output format for the synthesized speech"))
	EElevenLabsTTSOutputFormat OutputFormat{EElevenLabsTTSOutputFormat::MP3_22050_32};

	/** The ElevenLabs model ID to use for speech synthesis */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS|Request",
		Meta = (ToolTip = "The ElevenLabs model ID to use for speech synthesis"))
	FString ModelId{"eleven_flash_v2_5"};

	/** Text normalization settings for input processing */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS|Request",
		Meta = (ToolTip = "Text normalization settings for input processing"))
	EElevenLabsTTSTextNormalization TextNormalization{EElevenLabsTTSTextNormalization::AUTO};
};

/**
 * @enum EInworldRemoteTTSProvider
 * @brief Enumeration of supported remote TTS providers.
 */
UENUM(BlueprintType)
enum class EInworldRemoteTTSProvider : uint8
{
	/** Inworld's native TTS service */
	INWORLD,
	/** ElevenLabs TTS service */
	ELEVEN_LABS,
};

/**
 * @struct FInworldLocalTTSCreationConfig
 * @brief Configuration for creating local TTS instances.
 *
 * This structure defines the parameters for local TTS processing.
 * Currently, local TTS is not supported in this implementation.
 */
USTRUCT(BlueprintType)
struct FInworldLocalTTSCreationConfig
{
	GENERATED_BODY()
	// Local TTS not supported
};

/**
 * @struct FInworldRemoteTTSCreationConfig
 * @brief Configuration for creating remote TTS instances.
 *
 * This structure defines the parameters for remote TTS processing, including
 * provider selection and provider-specific synthesis configurations.
 */
USTRUCT(BlueprintType)
struct FInworldRemoteTTSCreationConfig
{
	GENERATED_BODY()

	/** The remote TTS provider to use (Inworld or ElevenLabs) */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		Meta = (ToolTip = "The remote TTS provider to use (Inworld or ElevenLabs)"))
	EInworldRemoteTTSProvider Provider{EInworldRemoteTTSProvider::INWORLD};

	/** Configuration for Inworld TTS synthesis when using Inworld provider */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		meta = (EditCondition = "Provider == EInworldRemoteTTSProvider::INWORLD", EditConditionHides,
			ToolTip = "Configuration for Inworld TTS synthesis when using Inworld provider"))
	FInworldTTSSpeechSynthesisConfig InworldSpeechSynthesisConfig{};

	/** Configuration for ElevenLabs TTS synthesis when using ElevenLabs provider */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		meta = (EditCondition = "Provider == EInworldRemoteTTSProvider::ELEVEN_LABS", EditConditionHides,
			ToolTip = "Configuration for ElevenLabs TTS synthesis when using ElevenLabs provider"))
	FElevenLabsTTSSpeechSynthesisConfig ElevenLabsSpeechSynthesisConfig{};
};

/**
 * @struct FInworldTTSCreationConfig
 * @brief Main configuration structure for creating TTS instances.
 *
 * This structure defines whether to use local or remote TTS processing
 * and contains the appropriate sub-configuration for the selected compute host.
 */
USTRUCT(BlueprintType)
struct FInworldTTSCreationConfig
{
	GENERATED_BODY()

	/** Whether to use local or remote compute host for TTS processing */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|TTS",
		Meta = (ToolTip = "Whether to use local or remote compute host for TTS processing"))
	EInworldComputeHost ComputeHost{EInworldComputeHost::REMOTE};

	/** Configuration for local TTS processing */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|TTS",
		meta = (EditCondition = "ComputeHost == EInworldComputeHost::LOCAL", EditConditionHides,
			ToolTip = "Configuration for local TTS processing (currently not supported)"))
	FInworldLocalTTSCreationConfig LocalCreationConfig{};

	/** Configuration for remote TTS processing */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|TTS",
		meta = (EditCondition = "ComputeHost == EInworldComputeHost::REMOTE", EditConditionHides,
			ToolTip = "Configuration for remote TTS processing"))
	FInworldRemoteTTSCreationConfig RemoteCreationConfig{};
};

/**
 * @struct FInworldVoice
 * @brief Configuration for voice selection in text-to-speech synthesis.
 *
 * This structure defines voice parameters for TTS operations, including
 * voice identifier and optional language specification.
 */
USTRUCT(BlueprintType)
struct FInworldVoice
{
	GENERATED_BODY()

	/** The unique identifier of the voice to use for synthesis */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS",
		Meta = (ToolTip = "The unique identifier of the voice to use for synthesis"))
	FString Id{"Olivia"};

	/** Whether to specify a language for the voice */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS",
		Meta = (ToolTip = "Whether to specify a language for the voice"))
	bool bHasLanguage{false};

	/** The language to use for the voice when bHasLanguage is true */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inworld|TTS",
		Meta = (EditCondition = "bHasLanguage", EditConditionHides,
			ToolTip = "The language to use for the voice when bHasLanguage is true"))
	EInworldLanguage Language{EInworldLanguage::ENGLISH};
};

/**
 * @struct FInworldTTSNodeExecutionConfig
 * @brief Runtime execution configuration for TTS nodes.
 *
 * This structure defines the runtime parameters for TTS node execution,
 * including component selection, voice configuration, and optional synthesis overrides.
 */
USTRUCT(BlueprintType)
struct FInworldTTSNodeExecutionConfig
{
	GENERATED_BODY()

	/** The TTS component ID to use for synthesis */
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Inworld",
		Meta = (GetOptions = "InworldRuntimeSettings.GetTTSIds", ToolTip = "The TTS component ID to use for synthesis"))
	FString TTSComponentId{"Default"};

	/** Voice configuration for text-to-speech synthesis */
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Inworld",
		Meta = (ToolTip = "Voice configuration for text-to-speech synthesis"))
	FInworldVoice Voice;

	/** Whether to override the default speech synthesis configuration */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		Meta = (ToolTip = "Whether to override the default speech synthesis configuration"))
	bool bOverrideSpeechSynthesisConfig{false};

	/** TTS provider to use when overriding synthesis configuration */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		meta = (EditCondition = "bOverrideSpeechSynthesisConfig", EditConditionHides,
			ToolTip = "TTS provider to use when overriding synthesis configuration"))
	EInworldRemoteTTSProvider Provider{EInworldRemoteTTSProvider::INWORLD};

	/** Inworld synthesis configuration override */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		meta = (EditCondition = "bOverrideSpeechSynthesisConfig && Provider == EInworldRemoteTTSProvider::INWORLD",
			EditConditionHides, ToolTip = "Inworld synthesis configuration override"))
	FInworldTTSSpeechSynthesisConfig InworldSpeechSynthesisConfig{};

	/** ElevenLabs synthesis configuration override */
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inworld|LLM",
		meta = (EditCondition = "bOverrideSpeechSynthesisConfig && Provider == EInworldRemoteTTSProvider::ELEVEN_LABS",
			EditConditionHides, ToolTip = "ElevenLabs synthesis configuration override"))
	FElevenLabsTTSSpeechSynthesisConfig ElevenLabsSpeechSynthesisConfig{};
};

/** Native delegate called when TTS primitive creation completes with interface access */
DECLARE_DELEGATE_OneParam(FOnInworldTTSPrimitiveCreatedNative, TSharedPtr<inworld::TTSInterface> /*TTS*/);

namespace inworld
{

class LocalTTSConfig;
/**
 * @brief Converts Unreal local TTS creation configuration to internal local TTS configuration.
 * @param In The Unreal local TTS creation configuration to convert
 * @param Out The internal local TTS configuration to populate
 */
void Convert(const FInworldLocalTTSCreationConfig& In, inworld::LocalTTSConfig& Out);

class RemoteTTSConfig;
/**
 * @brief Converts Unreal remote TTS creation configuration to internal remote TTS configuration.
 * @param In The Unreal remote TTS creation configuration to convert
 * @param Out The internal remote TTS configuration to populate
 */
void Convert(const FInworldRemoteTTSCreationConfig& In, inworld::RemoteTTSConfig& Out);

class SpeechSynthesisPostprocessingConfig;
/**
 * @brief Converts Unreal speech synthesis postprocessing configuration to internal configuration.
 * @param In The Unreal postprocessing configuration to convert
 * @param Out The internal postprocessing configuration to populate
 */
void Convert(const FInworldSpeechSynthesisPostprocessingConfig& In, inworld::SpeechSynthesisPostprocessingConfig& Out);

class SpeechSynthesisInferenceConfig;
/**
 * @brief Converts Unreal speech synthesis inference configuration to internal configuration.
 * @param In The Unreal inference configuration to convert
 * @param Out The internal inference configuration to populate
 */
void Convert(const FInworldSpeechSynthesisInferenceConfig& In, inworld::SpeechSynthesisInferenceConfig& Out);

class InworldSpeechSynthesisConfig;
/**
 * @brief Converts Unreal Inworld TTS speech synthesis configuration to internal configuration.
 * @param In The Unreal speech synthesis configuration to convert
 * @param Out The internal speech synthesis configuration to populate
 */
void Convert(const FInworldTTSSpeechSynthesisConfig& In, inworld::InworldSpeechSynthesisConfig& Out);

/**
 * @brief Converts ElevenLabs TTS output format enum to string representation.
 * @param In The output format enum to convert
 * @param Out The string representation to populate
 */
void Convert(const EElevenLabsTTSOutputFormat& In, FString& Out);

class ElevenLabsSpeechSynthesisConfig;
/**
 * @brief Converts Unreal ElevenLabs TTS speech synthesis configuration to internal configuration.
 * @param In The Unreal ElevenLabs configuration to convert
 * @param Out The internal ElevenLabs configuration to populate
 */
void Convert(const FElevenLabsTTSSpeechSynthesisConfig& In, inworld::ElevenLabsSpeechSynthesisConfig& Out);

class Voice;
/**
 * @brief Converts Unreal voice configuration to internal voice configuration.
 * @param In The Unreal voice configuration to convert
 * @param Out The internal voice configuration to populate
 */
void Convert(const FInworldVoice& In, inworld::Voice& Out);

/**
 * @brief Converts internal voice configuration to Unreal voice configuration.
 * @param In The internal voice configuration to convert
 * @param Out The Unreal voice configuration to populate
 */
void Convert(const inworld::Voice& In, FInworldVoice& Out);

class TTSNodeExecutionConfig;
/**
 * @brief Converts Unreal TTS node execution configuration to internal configuration.
 * @param In The Unreal TTS node execution configuration to convert
 * @param Out The internal TTS node execution configuration to populate
 */
void Convert(const FInworldTTSNodeExecutionConfig& In, inworld::TTSNodeExecutionConfig& Out);

}	 // namespace inworld
