#pragma once

#include <trx/game/music/enum.h>
#include <trx/game/music/ids.h>
#include <trx/game/music/types.h>

#include <stdint.h>

#define MUSIC_MAX_OVERLAY_TRACKS 3

typedef struct {
    MUSIC_ID track_id;
    MUSIC_PLAY_MODE mode;
    double timestamp;
} MUSIC_STREAM_STATE;

bool Music_Init(void);

// Stops playing current track and plays a single track.
//
// MPM_ONCE:
//   Plays the track once. Once playback is done, if there is an active looped
//   track, the playback resumes from the start of the looped track.
// MPM_LOOP:
//   Activates looped playback for the chosen track.
// MPM_NO_REPEAT:
//   A track with this play mode will not trigger in succession.
// MPM_DELAY:
//   A track does not get played and instead is only marked for later playback.
//   The track to play is available with Music_GetDelayedTrack().
// MPM_OVERLAY:
//   Plays a non-looping track without interrupting active background music.
// Returns the stream slot the track plays in - the main stream is slot 0, the
// overlays slots 1.. - or -1 when it does not play, which includes a track
// marked for later (delay) or a deferred ambient.
int32_t Music_Play_Direct(MUSIC_ID track, MUSIC_PLAY_MODE mode);

// Stops the provided single track and restarts the looped track if applicable.
void Music_StopTrack_Direct(MUSIC_ID track);

// Play a music track with a semantical ID that will get mapped to a specific
// music track slot depending on the game. Returns the stream slot, as
// Music_Play_Direct does, or -1.
int32_t Music_Play(MUSIC_TRX_ID track, MUSIC_PLAY_MODE mode);

// Returns true when the active backend can play the given direct track ID.
bool Music_IsTrackAvailable_Direct(MUSIC_ID track);

// Returns one past the largest direct track ID worth probing on the active
// backend, or 0 if no backend is available.
int32_t Music_GetTrackLimit(void);

// Resolves a track to its file path, freshly allocated for the caller to free,
// or nullptr when there is no file for it: a CD-audio backend, or a track the
// level does not carry.
char *Music_GetTrackPath(MUSIC_ID track);

// Stops all music streams, including looped, active, and overlay tracks.
void Music_Stop(void);

// Pauses the music.
void Music_Pause(void);

// Unpauses the music.
void Music_Unpause(void);

// Get the current timestamp of the current stream in seconds.
double Music_GetTimestamp(void);

// Seek to timestamp of current stream.
bool Music_SeekTimestamp(double timestamp);

// Seeks to the given timestamp if the drift is too big.
bool Music_SyncTimestamp(double timestamp);

// Returns the number of currently active serializable streams.
int32_t Music_GetStreamCount(void);

// Returns stream state by active index [0..Music_GetStreamCount()).
bool Music_GetStreamState(int32_t index, MUSIC_STREAM_STATE *state);

// The number of stream slots: the main stream, then the overlay slots. Unlike
// Music_GetStreamCount, this is fixed and addresses a slot whether it is active
// or not: slot 0 is the main stream, slots 1.. are the overlays.
int32_t Music_GetStreamSlotCount(void);

// Fills state for a stream slot. Returns false when the slot is inactive.
bool Music_GetStreamSlotState(int32_t slot, MUSIC_STREAM_STATE *state);

// Stops the stream in a slot. The main slot resumes the deferred ambient loop,
// as Music_StopTrack_Direct does; an overlay slot just closes.
void Music_StopStream(int32_t slot);

// Pauses or resumes the stream in a slot.
void Music_PauseStream(int32_t slot);
void Music_UnpauseStream(int32_t slot);

// Seeks the stream in a slot to a timestamp. Returns false when the slot is
// inactive.
bool Music_SeekStream(int32_t slot, double timestamp);

// Seeks timestamp for the active stream that matches track and mode.
bool Music_SeekTrackTimestamp(
    MUSIC_ID track, MUSIC_PLAY_MODE mode, double timestamp);

// Returns the delayed track. Ignores looped tracks.
MUSIC_ID Music_GetDelayedTrack(void);

// Returns the currently playing track. Includes looped music.
MUSIC_ID Music_GetCurrentPlayingTrack(void);

// Returns the looped track.
MUSIC_ID Music_GetCurrentLoopedTrack(void);

// Sets the game volume.
void Music_SetVolume(float volume);

// Resets all track trigger state.
void Music_ResetTrackStates(void);

// Returns the accumulated trigger state for the given track.
MUSIC_TRACK_STATE *Music_GetTrackState(MUSIC_ID track_id);

// Applies a trigger to the track, playing or stopping it per the OG rules.
void Music_Trigger(MUSIC_ID track_id, const MUSIC_TRIGGER *trigger);
