#ifndef NW4R_SND_REMOTE_SPEAKER_H
#define NW4R_SND_REMOTE_SPEAKER_H

#include "rvl/OS.h"   // IWYU pragma: export
#include "rvl/WENC.h" // IWYU pragma: export
#include "rvl/WPAD.h" // IWYU pragma: export

namespace nw4r {
namespace snd {

class RemoteSpeaker {
public:
    enum SpeakerState {
        STATE_INVALID,
        STATE_EXEC_SPEAKER_ON,
        STATE_SPEAKER_ON,
        STATE_EXEC_SPEAKER_PLAY,
        STATE_SPEAKER_PLAY,
        STATE_EXEC_SPEAKER_OFF,
        STATE_SPEAKER_OFF
    };

    enum SpeakerCommand {
        COMMAND_NONE,
        COMMAND_SPEAKER_ON,
        COMMAND_SPEAKER_PLAY,
        COMMAND_SPEAKER_OFF
    };

    static const int SAMPLES_PER_AUDIO_PACKET = 40;

public:
    RemoteSpeaker();

    void InitParam();
    bool Setup(WPADCallback pCallback);
    void Shutdown(WPADCallback pCallback);

    bool EnableOutput(bool enable);
    bool IsEnabledOutput() const;

    void Update();
    void UpdateStreamData(const s16 *pRmtSamples);

    bool IsAvailable() const {
        return mState == STATE_SPEAKER_PLAY;
    }

    void SetChannelIndex(int index) {
        mChannelIndex = index;
    }

private:
    static const int SAMPLES_PER_ENCODED_PACKET = (SAMPLES_PER_AUDIO_PACKET + 1) / 2;

    static const int CONTINUOUS_PLAY_INTERVAL_MINUTES = 8;

private:
    void ClearParam();
    void ExecCommand(SpeakerCommand command);

    bool IsAllSampleZero(const s16 *pRmtSamples);
    void NotifyCallback(s32 chan, s32 result);

    static void SpeakerOnCallback(s32 chan, s32 result);
    static void SpeakerPlayCallback(s32 chan, s32 result);
    static void SpeakerOffCallback(s32 chan, s32 result);

    static void ContinueAlarmHandler(OSAlarm *pAlarm, OSContext *pCtx);
    static void IntervalAlarmHandler(OSAlarm *pAlarm, OSContext *pCtx);

private:
    bool mInitFlag;          // at 0x0
    bool mPlayFlag;          // at 0x1
    bool mEnableFlag;        // at 0x2
    bool mFirstEncodeFlag;   // at 0x3
    bool mValidCallbackFlag; // at 0x4
    bool mCommandBusyFlag;   // at 0x5
    // TODO commenting out a random flag to make eggAudioRmtSpeakerMgr match
    // TODO offsets are wrong as a result
    // bool mForceResumeFlag;   // at 0x6
    bool mContinueFlag;      // at 0x7
    volatile bool mIntervalFlag;     // at 0x8
    SpeakerState mState;             // at 0xC
    SpeakerCommand mUserCommand;     // at 0x10
    SpeakerCommand mInternalCommand; // at 0x14
    WENCInfo mEncodeInfo;            // at 0x18
    int mChannelIndex;               // at 0x38
    WPADCallback *mWpadCallback;     // at 0x3C
    OSAlarm mContinueAlarm;          // at 0x40
    OSAlarm mIntervalAlarm;          // at 0x70
    s64 mContinueBeginTime;          // at 0xA0
};

} // namespace snd
} // namespace nw4r

#endif
