package net.accelf.yuito

import android.text.Spanned
import android.util.Log
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.appstore.StatusDeletedEvent
import com.keylesspalace.tusky.appstore.StreamUpdateEvent
import com.keylesspalace.tusky.entity.Filter
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.entity.StreamEvent
import com.keylesspalace.tusky.fragment.TimelineFragment
import com.keylesspalace.tusky.json.SpannedTypeAdapter
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener

class TimelineStreamingListener(private val eventHub: EventHub,
                                private val kind: TimelineFragment.Kind,
                                private val identifier: String? = null) : WebSocketListener() {

    private val gson = buildGson()
    private val target = if (identifier == null) { kind.name } else { kind.name + ":" + identifier }
    private var isFirstStatus = true

    override fun onOpen(webSocket: WebSocket, response: Response) {
        Log.d(TAG, "Stream connected to: $target")
    }

    override fun onMessage(webSocket: WebSocket, text: String) {
        val event = gson.fromJson(text, StreamEvent::class.java)
        val payload = event.payload
        when (event.event) {
            StreamEvent.EventType.UPDATE -> {
                val status = gson.fromJson(payload, Status::class.java)
                eventHub.dispatch(StreamUpdateEvent(status, kind, identifier, isFirstStatus))
                if (isFirstStatus) {
                    isFirstStatus = false
                }
            }
            StreamEvent.EventType.DELETE -> eventHub.dispatch(StatusDeletedEvent(payload))
            StreamEvent.EventType.FILTERS_CHANGED -> eventHub.dispatch(PreferenceChangedEvent(Filter.HOME)) // It may be not a home but it doesn't matter
            else -> Log.d(TAG, "Unsupported event type.")
        }
    }

    override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
        Log.d(TAG, "Stream closed for: $target")
    }

    companion object {
        private const val TAG = "StreamingListener"

        private fun buildGson(): Gson {
            return GsonBuilder()
                    .registerTypeAdapter(Spanned::class.java, SpannedTypeAdapter())
                    .create()
        }
    }

}
