package me.eternal.purrfectsnap.common.util.snap

import me.eternal.purrfectsnap.common.Constants
import me.eternal.purrfectsnap.common.util.ktx.await
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.InputStream
import java.util.Base64

object RemoteMediaResolver {
    const val CF_ST_CDN_D = "https://cf-st.sc-cdn.net/d/"

    val okHttpClient = OkHttpClient.Builder()
        .followRedirects(true)
        .retryOnConnectionFailure(true)
        .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
        .build()

    fun newResolveRequest(protoKey: ByteArray): Request {
        return Request.Builder()
            .url("https://gcp.api.snapchat.com/bolt-http/resolve?co=" + Base64.getUrlEncoder().encodeToString(protoKey))
            .addHeader("User-Agent", Constants.USER_AGENT)
            .build()
    }

    suspend inline fun downloadMedia(url: String, decryptionCallback: (InputStream) -> InputStream = { it }, result: (InputStream, Long) -> Unit) {
        okHttpClient.newCall(Request.Builder().url(url).build()).await().use { response ->
            if (!response.isSuccessful) {
                throw Throwable("invalid response ${response.code}")
            }
            result(decryptionCallback(response.body.byteStream()), response.body.contentLength())
        }
    }

    suspend inline fun downloadBoltMedia(
        protoKey: ByteArray,
        decryptionCallback: (InputStream) -> InputStream = { it },
        resultCallback: (stream: InputStream, length: Long) -> Unit
    ) {
        okHttpClient.newCall(newResolveRequest(protoKey)).await().use { response ->
            if (!response.isSuccessful) {
                throw Throwable("invalid response ${response.code}")
            }
            resultCallback(
                decryptionCallback(
                    response.body.byteStream()
                ),
                response.body.contentLength()
            )
        }
    }

    fun getMediaHeaders(protoKey: ByteArray): Headers {
        val request = newResolveRequest(protoKey)
        return okHttpClient.newCall(request.newBuilder().method("HEAD", null).build()).execute().headers
    }
}
