package com.ponzischeme89.memby.ui.player

/**
 * Times the stages between pressing Play and seeing a frame.
 *
 * "Playback is slow" is not something that can be acted on: the wait is shared between
 * negotiating a stream with the server, starting the activity, opening the file over HTTP
 * and initialising a decoder, and on a weak television any one of them can dominate.
 * Cumulative marks make the log say which.
 *
 * Marks are cumulative from the moment the viewer pressed Play — the interesting number is
 * always "how long had they been waiting", not how long one step took in isolation — and
 * [summary] prints the per-stage deltas beside them so both readings are available. Pure
 * and clock-injected so the arithmetic is unit-testable; [PlayerActivity] supplies
 * `SystemClock.elapsedRealtime`.
 */
internal class PlaybackTrace(
    private val startedAtMs: Long,
    private val clock: () -> Long,
) {
    private val marks = LinkedHashMap<String, Long>()

    /** Records [stage] at the current time and returns milliseconds since Play was pressed. */
    fun mark(stage: String): Long {
        val elapsed = (clock() - startedAtMs).coerceAtLeast(0L)
        // A stage only ever happens once per launch; a repeat is a retry, and the first
        // time the viewer reached that point is the one that describes their wait.
        marks.putIfAbsent(stage, elapsed)
        return marks.getValue(stage)
    }

    fun elapsedMs(): Long = (clock() - startedAtMs).coerceAtLeast(0L)

    /**
     * One line naming every stage reached, as `stage=cumulative(+delta)`. Stages that never
     * happened are simply absent rather than reported as zero — on the resume path there is
     * no pre-roll, and a launch that reused a prefetched stream never resolved one.
     */
    fun summary(): String {
        var previous = 0L
        return marks.entries.joinToString(" ") { (stage, elapsed) ->
            val delta = (elapsed - previous).coerceAtLeast(0L)
            previous = elapsed
            "$stage=${elapsed}ms(+${delta}ms)"
        }
    }

    companion object {
        /** The viewer's Play press has been handled and the player activity is alive. */
        const val ACTIVITY_CREATED = "activity"

        /** The ExoPlayer instance exists and its renderers are built. */
        const val PLAYER_BUILT = "player"

        /** A stream URL is in hand, whether from the launch prefetch or a fresh request. */
        const val STREAM_RESOLVED = "stream"

        /** [androidx.media3.exoplayer.ExoPlayer.prepare] has been called. */
        const val PREPARED = "prepared"

        /** The player reported it has buffered enough to play. */
        const val READY = "ready"

        /** A frame is on the screen. This is the number the viewer actually experiences. */
        const val FIRST_FRAME = "first_frame"
    }
}
