package com.fabledsword.minstrel.player

import com.fabledsword.minstrel.api.endpoints.PlaybackErrorReportRequest
import com.fabledsword.minstrel.api.endpoints.PlaybackErrorsApi
import com.fabledsword.minstrel.auth.AuthStore
import com.fabledsword.minstrel.cache.mutations.MutationQueue
import com.fabledsword.minstrel.cache.mutations.PlaybackErrorReportPayload
import retrofit2.Retrofit
import retrofit2.create
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Writes a [PlaybackErrorEvent] to the server. Follows the standing
 * offline-first rule for server writes: try the POST first, fall back
 * to the MutationQueue on transport failure so a tracked report is
 * never lost.
 *
 * Reused client_id comes from [AuthStore.clientId] — the same UUID-
 * per-install identifier the play-events reporter already sends, so
 * support can correlate playback errors with the surrounding plays.
 */
@Singleton
class PlaybackErrorRepository @Inject constructor(
    private val authStore: AuthStore,
    private val mutationQueue: MutationQueue,
    retrofit: Retrofit,
) {
    private val api: PlaybackErrorsApi = retrofit.create()

    /**
     * Reports a playback failure. Returns [Outcome.ACCEPTED] on a 2xx,
     * [Outcome.QUEUED] when the call was buffered to the MutationQueue
     * for later replay. Never throws — callers don't need a try block.
     */
    suspend fun report(event: PlaybackErrorEvent): Outcome {
        val clientId = resolveClientId()
        val payload = PlaybackErrorReportPayload(
            trackId = event.trackId,
            kind = event.kind,
            detail = event.detail,
            clientId = clientId,
        )
        return try {
            api.report(
                PlaybackErrorReportRequest(
                    trackId = payload.trackId,
                    kind = payload.kind,
                    detail = payload.detail,
                    clientId = payload.clientId,
                ),
            )
            Outcome.ACCEPTED
        } catch (
            @Suppress("TooGenericExceptionCaught", "SwallowedException") e: Throwable,
        ) {
            // Intentional swallow — see LikesRepository.toggleLike for
            // the same offline-first rationale.
            mutationQueue.enqueuePlaybackErrorReport(payload)
            Outcome.QUEUED
        }
    }

    /**
     * Returns the persisted client id, generating + persisting one on
     * first read. Mirrors [PlayEventsReporter.resolveClientId] — the
     * value is shared across all client-id-carrying surfaces.
     */
    private fun resolveClientId(): String {
        authStore.clientId.value?.let { return it }
        val fresh = UUID.randomUUID().toString()
        authStore.setClientId(fresh)
        return fresh
    }

    enum class Outcome { ACCEPTED, QUEUED }
}
