package net.buzzert.kordophone.backend.server

import com.auth0.android.jwt.JWT
import com.google.gson.annotations.SerializedName
import net.buzzert.kordophone.backend.model.Conversation
import net.buzzert.kordophone.backend.model.GUID
import net.buzzert.kordophone.backend.model.Message
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
import java.lang.Error
import java.lang.Exception

data class SendMessageRequest(
    @SerializedName("guid")
    val conversationGUID: String,

    @SerializedName("body")
    val body: String,

    @SerializedName("fileTransferGUIDs")
    val transferGUIDs: List<String>?,
)

data class SendMessageResponse(
    @SerializedName("guid")
    val sentMessageGUID: String,
)

data class AuthenticationRequest(
    @SerializedName("username")
    val username: String,

    @SerializedName("password")
    val password: String,
)

data class AuthenticationResponse(
    @SerializedName("jwt")
    val serializedToken: String,
) {
    fun decodeToken(): JWT {
        return JWT(serializedToken)
    }
}

data class UploadAttachmentResponse(
    @SerializedName("fileTransferGUID")
    val transferGUID: String
)

interface APIInterface {
    @GET("version")
    suspend fun getVersion(): ResponseBody

    @GET("conversations")
    suspend fun getConversations(): Response<List<Conversation>>

    @GET("messages")
    suspend fun getMessages(
        @Query("guid") conversationGUID: String,
        @Query("limit") limit: Int? = null,
        @Query("beforeMessageGUID") beforeMessageGUID: GUID? = null,
        @Query("afterMessageGUID") afterMessageGUID: GUID? = null,
    ): Response<List<Message>>

    @POST("sendMessage")
    suspend fun sendMessage(@Body request: SendMessageRequest): Response<SendMessageResponse>

    @POST("markConversation")
    suspend fun markConversation(@Query("guid") conversationGUID: String): Response<Void>

    @GET("attachment")
    suspend fun fetchAttachment(@Query("guid") guid: String, @Query("preview") preview: Boolean = false): ResponseBody

    @POST("uploadAttachment")
    suspend fun uploadAttachment(@Query("filename") filename: String, @Body body: RequestBody): Response<UploadAttachmentResponse>

    @POST("authenticate")
    suspend fun authenticate(@Body request: AuthenticationRequest): Response<AuthenticationResponse>
}

class ResponseDecodeError(val response: ResponseBody): Exception(response.string())

fun <T> Response<T>.bodyOnSuccessOrThrow(): T {
    if (isSuccessful) {
        return body()!!
    }

    throw ResponseDecodeError(errorBody()!!)
}
