package xyz.magicalbits.smsremote.network

import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.auth.Auth
import io.ktor.client.plugins.auth.providers.BearerTokens
import io.ktor.client.plugins.auth.providers.bearer
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.net.URLEncoder

class NetworkClient {
    // TODO make apiBaseUrl configurable with fallback to my real domain
    private val apiBaseUrl = "http://192.168.1.116:5000"

    // TODO ask user for creds, call login endpoint, store tokens in local encrypted storage

    private val networkClient = HttpClient(CIO) {
        install(Auth) {
            bearer {
                // TODO configure refresh token so it refreshes the access token
                loadTokens {
                    // TODO load from local encrypted storage
                    BearerTokens(
                        "test",
                        "test"
                    )
                }
            }
        }
    }

    @Serializable()
    data class DeviceDto(val access_key: String, val name: String, val type: String)

    @Serializable
    data class SimCardDto(val device_access_key: String, val phone_number: String)

    @Serializable
    data class SmsMessageDto(val content: String, val ts_received: Int, val ts_sent: Int, val msg_type: String, val local_phone_number: String, val remote_phone_number: String)

    // GET /api/v1/devices
    suspend fun getDevices(): List<DeviceDto> {
        // TODO handle non-200 status codes
        // TODO handle '{"msg":"Token has expired"}' messages
        val data = networkClient.get("$apiBaseUrl/api/v1/devices").bodyAsText()
        return Json.decodeFromString(data)
    }

    // GET /api/v1/sim-cards
    suspend fun getSimCardsByAccessKey(accessKey: String): List<SimCardDto> {
        // TODO handle non-200 status codes
        // TODO handle '{"msg":"Token has expired"}' messages
        val data = networkClient.get("$apiBaseUrl/api/v1/sim-cards?access_key=$accessKey").bodyAsText()
        return Json.decodeFromString(data)
    }

    // GET /api/v1/sms-messages
    suspend fun getSmsMessagesByLocalPhoneNumber(phoneNumber: String): List<SmsMessageDto> {
        // TODO handle non-200 status codes
        // TODO handle '{"msg":"Token has expired"}' messages
        // TODO extract encoder to a function here or to a utility class
        val encodedPhoneNumber = withContext(Dispatchers.IO) {
            URLEncoder.encode(phoneNumber, "UTF-8")
        }
        val data = networkClient.get("$apiBaseUrl/api/v1/sms-messages?local_phone_number=$encodedPhoneNumber").bodyAsText()
        return Json.decodeFromString(data)
    }
}
