package de.kif.frontend

import de.kif.common.MessageBox
import de.kif.common.MessageType
import de.kif.common.RepositoryType
import de.kif.frontend.repository.*
import de.westermann.kwebview.clearInterval
import de.westermann.kwebview.createHtmlView
import de.westermann.kwebview.interval
import kotlinx.serialization.DynamicObjectParser
import org.w3c.dom.get
import org.w3c.xhr.XMLHttpRequest
import kotlin.browser.document
import kotlin.browser.window

class PushServiceClient {
    private val prefix = js("prefix")
    private val url = "$prefix/api/updates"
    private val body = document.body ?: createHtmlView()
    private val parser = DynamicObjectParser()

    private var timestamp = body.dataset["timestamp"]?.toLongOrNull() ?: 0L
    private val signature = body.dataset["signature"] ?: ""
    private var intervalId: Int? = null

    private fun reload() {
        val id = intervalId ?: return
        clearInterval(id)
        intervalId = null

        window.location.reload()
    }

    private fun onMessage(messageBox: MessageBox) {
        body.classList.remove("offline")

        if (messageBox.valid && signature == messageBox.signature) {
            timestamp = messageBox.timestamp

            for (message in messageBox.messages) {
                for (handler in messageHandlers) {
                    if (handler.repository == message.repository) {
                        when (message.type) {
                            MessageType.CREATE -> handler.onCreate(message.id)
                            MessageType.UPDATE -> handler.onUpdate(message.id)
                            MessageType.DELETE -> handler.onDelete(message.id)
                        }
                    }
                }
            }
        } else {
            reload()
        }
    }

    private fun onError(code: Int) {
        if (!body.classList.contains("offline")) {
            console.log("Offline reason: $code")
        }
        body.classList.add("offline")
    }

    private fun request() {
        val xmlHttpRequest = XMLHttpRequest()

        xmlHttpRequest.onreadystatechange = {
            try {
                if (xmlHttpRequest.readyState == 4.toShort()) {
                    if (xmlHttpRequest.status == 200.toShort() || xmlHttpRequest.status == 304.toShort()) {
                        val json = JSON.parse<JsonResponse>(xmlHttpRequest.responseText)

                        if (json.OK) {
                            val message = parser.parse(json.data, MessageBox.serializer())
                            onMessage(message)
                        } else {
                            onError(-1)
                        }

                    } else {
                        onError(xmlHttpRequest.status.toInt())
                    }
                }
            } catch (e: Exception) {
                console.error(e)
                onError(-2)
            }
        }
        xmlHttpRequest.open("GET", "$url?timestamp=$timestamp", true)
        xmlHttpRequest.overrideMimeType("application/json")
        xmlHttpRequest.send()
    }

    private val messageHandlers: List<MessageHandler> = listOf(
        RoomRepository.handler,
        ScheduleRepository.handler,
        TrackRepository.handler,
        UserRepository.handler,
        WorkGroupRepository.handler,
        PostRepository.handler,
        AnnouncementRepository.handler
    )

    init {
        intervalId = interval(500) {
            request()
        }
    }
}

abstract class MessageHandler(val repository: RepositoryType) {
    abstract fun onCreate(id: Long)
    abstract fun onUpdate(id: Long)
    abstract fun onDelete(id: Long)
}
