package com.fabledsword.minstrel.api.endpoints

import kotlinx.serialization.Serializable
import retrofit2.http.Body
import retrofit2.http.POST

/**
 * Retrofit interface for the cast-token endpoint. Used by the UPnP
 * selection path in `OutputPickerController` to obtain a signed stream
 * URL that a network speaker can fetch without the user's session
 * cookie — those devices cannot carry the session, so the signed
 * query string is the only way they can fetch the bytes.
 *
 * Endpoint: `POST /api/cast/stream-token`
 * Auth: standard session cookie (`AuthCookieInterceptor` handles it).
 *
 * Server contract lives at `internal/api/cast_token.go`
 * (commit e774097f). Field names here mirror the server's `json:`
 * tags verbatim — `trackId` / `expSeconds` — so no `@SerialName` is
 * needed on the request, and `token` / `exp` / `url` map straight
 * through on the response.
 */
interface CastApi {
    @POST("api/cast/stream-token")
    suspend fun streamToken(@Body req: StreamTokenRequest): StreamTokenResponse
}

/**
 * Request body. [expSeconds] is clamped server-side to [60, 86400];
 * the 21_600 default (6h) is long enough to play through any typical
 * track without re-minting mid-playback.
 */
@Serializable
data class StreamTokenRequest(
    val trackId: String,
    val expSeconds: Int = 21_600,
)

/**
 * Response body. [url] is a fully-formed stream URL with [token] and
 * [exp] already embedded as query params — callers pass it verbatim
 * to `AVTransport.SetAVTransportURI`. [mime] + [title] are the bits
 * the client needs to build DIDL-Lite metadata for that call: Sonos
 * rejects empty DIDL with vendor error 1023, so the server hands back
 * the track's MIME (from `tracks.file_format`) and title so the
 * client can populate `<res protocolInfo>` and `<dc:title>` without
 * a follow-up round trip.
 */
@Serializable
data class StreamTokenResponse(
    val token: String,
    val exp: Long,
    val url: String,
    val mime: String = "audio/mpeg",
    val title: String = "",
)
