//
// Audio playback. The track download is async — `audio_play_track` returns
// immediately after queueing the request; when the bytes arrive we decode
// them and start a Sound_Player stream.
//
// Pause is REAL: setting `current_rate = desired_rate = 0` freezes the
// stream's play_cursor and (with `inaudible = true`) silences output. So
// while paused the seek bar doesn't drift and auto-advance can't fire.
//

audio_play_track :: (track: Track) {
    if !app.audio_inited  return;

    pending := New(Track);
    pending.* = clone_track(track);

    // /universal lets the server pick the best format, transcoding to mp3
    // when the original isn't in our `container` list. Without this, Opus /
    // M4A / AAC / WMA / ALAC files come back as bytes we can't decode.
    path := tprint(
        "/Audio/%/universal?container=mp3,flac,ogg,wav&audioCodec=mp3&maxStreamingBitrate=320000&userId=%&deviceId=%&api_key=%",
        track.id, app.jellyfin.user_id, DEVICE_ID, app.jellyfin.auth_token,
    );
    log_info("audio: downloading '%' (% ticks)", track.name, track.duration_ticks);
    http_submit("GET", path, on_done=on_track_downloaded, user_data=pending);
}

audio_toggle_pause :: () {
    if !app.current_stream  return;
    s := app.current_stream;
    app.paused = !app.paused;
    if app.paused {
        s.current_rate = 0;
        s.desired_rate = 0;
        s.inaudible    = true;
    } else {
        s.current_rate = 1;
        s.desired_rate = 1;
        s.inaudible    = false;
    }
}

audio_is_paused :: () -> bool {
    return app.paused;
}

audio_seek_seconds :: (seconds: float) {
    if !app.current_stream || !app.current_stream.sound_data  return;
    rate := cast(float64) app.current_stream.sound_data.sampling_rate;
    target := cast(float64) seconds * rate;
    if target < 0  target = 0;
    app.current_stream.play_cursor = target;
}

stop_current_stream :: () {
    if !app.current_stream  return;
    Sound.stop_stream_abruptly(app.current_stream.entity_id);
    app.current_stream = null;
}

sound_release_callback :: (stream: *Sound.Sound_Stream, data: *Sound.Sound_Data) {
    if stream && stream.entity_id == app.track_entity_id {
        app.track_finished = true;
        app.current_stream = null;
    }
}

clone_track :: (t: Track) -> Track {
    out: Track;
    out.id             = copy_string(t.id);
    out.name           = copy_string(t.name);
    out.album          = copy_string(t.album);
    out.album_id       = copy_string(t.album_id);
    out.artist         = copy_string(t.artist);
    out.duration_ticks = t.duration_ticks;
    out.index_number   = t.index_number;
    return out;
}

free_track :: (t: *Track) {
    free(t.id);
    free(t.name);
    free(t.album);
    free(t.album_id);
    free(t.artist);
    t.* = .{};
}

#scope_file

on_track_downloaded :: (task: *Http_Task) {
    pending := cast(*Track) task.user_data;
    defer { free_track(pending); free(pending); }

    if !task.response.ok {
        log_error("audio download '%' failed: status=%", pending.name, task.response.status_code);
        return;
    }

    bytes := task.response.body;
    task.response.body = "";

    sd, format, ok := decode_audio(bytes, pending.name);
    if !ok {
        log_error("audio decode failed for '%'", pending.name);
        free(bytes);
        return;
    }
    data := New(Sound.Sound_Data);
    data.* = sd;

    stop_current_stream();
    free_track(*app.current_track);
    app.current_track  = clone_track(pending.*);
    app.current_format = format;

    // New track always starts un-paused; user clicking Next/Prev or
    // auto-advance both want fresh playback state.
    app.paused = false;

    app.track_entity_id += 1;
    stream := Sound.make_stream(data, .MUSIC);
    stream.entity_id = app.track_entity_id;
    Sound.start_playing(stream);

    app.current_stream = stream;
    app.track_finished = false;
    log_info("audio: playing '% — %' [%]", app.current_track.artist, app.current_track.name, format);
}
