package at.lockstep.player.data import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.json.JSONObject import java.io.IOException sealed class MetadataFetchResult { data class Found(val collection: JSONObject) : MetadataFetchResult() data object NotFound : MetadataFetchResult() } class MetadataSyncClient( private val httpClient: OkHttpClient, private val baseUrl: String, ) { @Throws(IOException::class) fun fetchMetadata( accessToken: String, trackId: String, type: String, ): MetadataFetchResult { val url = baseUrl.toHttpUrl() .newBuilder() .addPathSegments("metadata") .addQueryParameter("trackId", trackId) .addQueryParameter("type", type) .build() val request = Request.Builder() .url(url) .addHeader("Authorization", "Bearer $accessToken") .get() .build() httpClient.newCall(request).execute().use { response -> if (response.code == 404) { return MetadataFetchResult.NotFound } val bodyText = response.body?.string().orEmpty() if (!response.isSuccessful) { val message = runCatching { JSONObject(bodyText).optString("error") } .getOrNull() ?.takeIf { it.isNotBlank() } ?: response.message throw IOException(message) } val collection = runCatching { JSONObject(bodyText).getJSONObject("collection") } .getOrNull() ?: throw IOException("Missing collection in response") return MetadataFetchResult.Found(collection) } } @Throws(IOException::class) fun uploadCollection( accessToken: String, trackId: String, type: String, version: Int, collection: JSONObject, ) { val payload = JSONObject() .apply { put("trackId", trackId) put("type", type) put("version", version) put("collection", collection) }.toString() val request = Request.Builder() .url("$baseUrl/metadata") .addHeader("Authorization", "Bearer $accessToken") .post(payload.toRequestBody(JSON_MEDIA)) .build() httpClient.newCall(request).execute().use { response -> if (response.isSuccessful) { return } val bodyText = response.body?.string().orEmpty() val message = runCatching { JSONObject(bodyText).optString("error") } .getOrNull() ?.takeIf { it.isNotBlank() } ?: response.message throw IOException(message) } } companion object { private val JSON_MEDIA = "application/json; charset=utf-8".toMediaType() } }