package ru.myitschool.work.data.source

import android.accounts.NetworkErrorException
import android.util.Log
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.HttpRequestData
import io.ktor.client.request.get
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText
import io.ktor.client.statement.request
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import ru.myitschool.work.core.Constants
import ru.myitschool.work.data.dto.PlaceDto
import ru.myitschool.work.data.dto.BookRequestDto
import ru.myitschool.work.data.dto.UserDto

object NetworkDataSource {
    private val client by lazy {
        HttpClient(CIO) {
            install(ContentNegotiation) {
                json(
                    Json {
                        isLenient = true
                        ignoreUnknownKeys = true
                        explicitNulls = true
                        encodeDefaults = true
                    }
                )
            }
        }
    }
    suspend fun getToken(login: String, password: String): Result<String> = withContext(Dispatchers.IO) {
        return@withContext runCatching {
            val response = client.post("${Constants.HOST}/api${Constants.GET_TOKEN}") {
                contentType(ContentType.Application.Json)
                setBody(
                    """
                       "login" : "$login",
                       "password" : "$password"
                    """.trimIndent()
                )
            }
            if (response.status != HttpStatusCode.OK) {
                error(response.status)
            }
            else if (response.status == HttpStatusCode.Unauthorized) {
                error("Неверный логин или пароль")
            }
            Log.e("getToken", response.status.toString())
            response.body<String>()
        }
    }
    suspend fun checkAuth(token: String): Result<Boolean> = withContext(Dispatchers.IO) {
        return@withContext runCatching {
            Log.e("token", token)
            val response = client.get(getUrl(token, Constants.AUTH_URL))
            when (response.status) {
                HttpStatusCode.OK -> true
                else -> false
            }
        }
    }

    suspend fun getInfo(token: String): Result<UserDto> = withContext(Dispatchers.IO) {
        return@withContext runCatching {
            println("!!!!!!!!!!!!!! getInfo $token")
            val response = client.get(getUrl(token, Constants.INFO_URL))
            if (response.status == HttpStatusCode.OK) {
                println("!!!!!!!!!!!!!! getInfo OK ${response.bodyAsText()}")
                Log.d("1", "!!!!!!!!!!!!!! getInfo OK ${response.bodyAsText()}")
                response.body<UserDto>()
            } else {
                println("!!!!!!!!!!!!!! getInfo ERROR ${response.bodyAsText()}")
                error(response.bodyAsText())
            }
        }
    }

    suspend fun getBooking(token: String): Result<Map<String, List<PlaceDto>>?> = withContext(Dispatchers.IO) {
        return@withContext runCatching {
            val response = client.get(getUrl(token, Constants.BOOKING_URL))
            if (response.status == HttpStatusCode.OK) {
                response.body<Map<String, List<PlaceDto>>>()
            } else {
                error(response.bodyAsText())
            }
        }
    }

    suspend fun addBook(token: String, data: BookRequestDto): Result<Boolean> = withContext(Dispatchers.IO) {
        return@withContext runCatching {
            val response = client.post(getUrl(token, Constants.BOOK_URL)) {
                contentType(ContentType.Application.Json)
                setBody(data)
            }
            when (response.status) {
                HttpStatusCode.Created -> true
                HttpStatusCode.Conflict -> false
                else -> error(response.bodyAsText())
            }
        }
    }

    private fun getUrl(token: String, targetUrl: String) = "${Constants.HOST}/api/$token$targetUrl"
}