package de.kif.frontend.repository

import de.kif.common.Repository
import de.kif.common.model.Model
import org.w3c.xhr.XMLHttpRequest
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import kotlin.js.Promise

suspend fun repositoryGet(
    url: String
): dynamic {
    val promise = Promise<dynamic> { resolve, reject ->
        val xhttp = XMLHttpRequest()

        xhttp.onreadystatechange = {
            if (xhttp.readyState == 4.toShort()) {
                if (xhttp.status == 200.toShort() || xhttp.status == 304.toShort()) {
                    resolve(JSON.parse(xhttp.responseText))
                } else {
                    reject(NoSuchElementException("${xhttp.status}: ${xhttp.statusText}"))
                }
            }
        }
        xhttp.open("GET", url, true)

        xhttp.send()
    }

    try {
        val d = promise.await()

        return if (d.OK) {
            d.data
        } else {
            null
        }
    } catch (e: NoSuchElementException) {
        console.error(e)

        return null
    }
}

suspend fun repositoryPost(
    url: String,
    data: String? = null
): dynamic {
    val promise = Promise<dynamic> { resolve, reject ->
        val xhttp = XMLHttpRequest()

        xhttp.onreadystatechange = {
            if (xhttp.readyState == 4.toShort()) {
                if (xhttp.status == 200.toShort() || xhttp.status == 304.toShort()) {
                    resolve(JSON.parse(xhttp.responseText))
                } else {
                    reject(NoSuchElementException("${xhttp.status}: ${xhttp.statusText}"))
                }
            }
        }
        xhttp.open("POST", url, true)
        xhttp.setRequestHeader("Content-type", "application/json");

        xhttp.send(data)
    }

    try {
        val d = promise.await()

        return if (d.OK) {
            d.data
        } else {
            null
        }
    } catch (e: NoSuchElementException) {
        console.error(e)

        return null
    }
}

suspend fun repositoryRawGet(
    url: String
): String {
    val promise = Promise<String> { resolve, reject ->
        val xhttp = XMLHttpRequest()

        xhttp.onreadystatechange = {
            if (xhttp.readyState == 4.toShort()) {
                if (xhttp.status == 200.toShort() || xhttp.status == 304.toShort()) {
                    resolve(xhttp.responseText)
                } else {
                    reject(NoSuchElementException("${xhttp.status}: ${xhttp.statusText}"))
                }
            }
        }
        xhttp.open("GET", url, true)

        xhttp.send()
    }

    return promise.await()
}

suspend fun <T> Promise<T>.await(): T = suspendCoroutine { cont ->
    then({ cont.resume(it) }, { cont.resumeWithException(it) })
}

class RepositoryDelegate<T : Model>(
    private val repository: Repository<T>,
    private val id: Long
) {

    private var backing: T? = null

    suspend fun get(): T {
        if (backing == null) {
            backing = repository.get(id) ?: throw NoSuchElementException()
        }
        return backing!!
    }

    fun set(value: T) {
        backing = value
    }
}