package com.dtourolle.jellytau.player

/**
 * Whether the *player* is allowed to retry a failed load of what is currently
 * loaded, or whether recovery belongs to the backend instead.
 *
 * Pure state, deliberately free of any media3 or Android type so the decision is
 * unit-testable off-device — the same shape as `ScreenWakeState` (DR-202).
 *
 * ExoPlayer resumes a failed load in place only when it knows where "in place"
 * is: `ProgressiveMediaPeriod.configureRetry` keeps the load position when the
 * content length is known *or* the extractor produced a seek map with a
 * duration, and otherwise assumes the source is live — it resets every sample
 * queue and re-requests the URL from offset 0.
 *
 * The background-audio handoff transcode (UR-040) satisfies neither condition:
 * `/Audio/{id}/universal?Container=mp3&TranscodingProtocol=http` is chunked, so
 * there is no `Content-Length`, and a live mp3 encode carries no `Xing` header,
 * so the duration is unset — visible in logcat as every position tick reading
 * `<position> / 0.0`. Its URL carries `StartTimeTicks` = the handoff point, so a
 * restart from offset 0 drops playback back to where audio-only mode began and
 * carries on from there, and because that is a successful *retry* rather than a
 * failure, no error and no `STATE_ENDED` is ever reported: the app cannot see it
 * happen. That is the bug this exists to prevent (DR-203).
 *
 * Rust decides which streams those are and says so on every load; this only
 * remembers the answer for the load-error policy to read. Refusing the retry
 * turns the silent rewind into a recoverable error, which the backend answers by
 * re-opening the stream at the position playback actually reached (DR-129).
 *
 * TRACES: UR-040, UR-004 | DR-203 | UT-200
 */
class StreamRetryDecision {
    @Volatile
    private var nonResumableStream = false

    /**
     * Record what is being loaded.
     *
     * @param nonResumable whether re-requesting this stream would restart it
     *   rather than continue it — `player_retry_restarts_stream` in Rust.
     */
    fun onLoad(nonResumable: Boolean) {
        nonResumableStream = nonResumable
    }

    /** True while the player may handle a load error by retrying it itself. */
    val playerMayRetry: Boolean
        get() = !nonResumableStream
}
