// ------------------------------------------------
// Copyright Joe Marshall 2024- All Rights Reserved
// ------------------------------------------------
//
// Unreal IAudioOut implementation. This uses a
// USoundWaveProcedural to do the output, and also
// a UAudioComponent object. If given a parent
// actor object which has an existing
// UAudioComponent, it uses that. Otherwise it
// makes a new UAudioComponent and holds a strong
// object pointer to it until this class is
// destroyed.
// ------------------------------------------------
#pragma once

#include "Sound/SoundWaveProcedural.h"
#include <chrono>
#include <cstdint>

#include "IAudioOut.h"

#include "UnrealAudioOut.generated.h"

class USoundWaveProceduralWithTiming;
class UAudioComponent;
class UActorComponent;

UCLASS(MinimalAPI)
class USoundWaveProceduralWithTiming : public USoundWaveProcedural
{
    GENERATED_BODY()
  public:
    virtual int32 GeneratePCMData(uint8 *PCMData, const int32 SamplesNeeded) override;
    virtual void ResetAudio();
    virtual void QueueSilence(int64_t bytes);
    bool paused;
    bool hasTiming;
    int64_t lastBufSendTime;
};

class UnrealAudioOut : public IAudioOut
{
  public:
    explicit UnrealAudioOut(UActorComponent *owner);
    virtual ~UnrealAudioOut() override;
    virtual void init(int sampleRate, int channels) override;
    virtual void initSilent() override;
    virtual void close() override;
    virtual void sendBuffer(uint8_t *buf, int bufSize, int64_t presentationTimeNS,
                            bool reset = false) override;
    virtual int64_t getPresentationTimeNS() override; // current presentation time
    virtual IAudioOut::NsTime getWaitTimeForPresentationTime(int64_t presentationTimeNS,
                                                             int64_t maxDuration) override;
    virtual bool setVolume(float volume) override;
    virtual void setPlaying(bool playing) override;
    virtual bool setRate(float rate) override;
    virtual void onSeek(int64_t newPresentationTimeNS, bool resetAudio) override;
    virtual int64_t getQueuedTimeNS() override;
    virtual void onHasVideoTime(int64_t newPresentationTimeNS) override;

  private:
    TObjectPtr<USoundWaveProceduralWithTiming> audioSender;
    UActorComponent *owner;
    TWeakObjectPtr<UAudioComponent> audioComponent;
    TObjectPtr<UAudioComponent> audioComponentWeCreated;
    bool hasTimeOffset;
    int64_t presentationTimeOffset;
    int numChannels;
    int sampleRate;
    bool isPlaying;

    bool afterSeek;

    float playbackRate;

    int64_t pausedPresentationTime;
};
