package dev.zxq5.chatapp.android.core.service

import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.IBinder
import android.util.Log
import dev.zxq5.chatapp.android.ChatApplication
import dev.zxq5.chatapp.android.api.model.ChatEvent
import dev.zxq5.chatapp.android.data.repository.ChatRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch

class MessageStreamService : Service() {

    private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    private lateinit var notificationService: NotificationService
    private lateinit var chatRepository: ChatRepository

    var activeChannelId: Long? = null
        set(value) {
            field = value
            Log.d("Service", "activeChannelId set to $value")
            if (value != null) {
                currentStreamJob?.cancel()
                observeMessages()
            }
        }

    private var currentStreamJob: kotlinx.coroutines.Job? = null

    companion object {
        var instance: MessageStreamService? = null

        fun start(context: Context) {
            val intent = Intent(context, MessageStreamService::class.java)
            context.startService(intent)
        }

        fun stop(context: Context) {
            context.stopService(Intent(context, MessageStreamService::class.java))
        }
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
        notificationService = NotificationService(this)
        chatRepository = (application as ChatApplication).chatRepository
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        observeMessages()
        return START_STICKY
    }

    private fun observeMessages() {
        val channelId = activeChannelId ?: chatRepository.getLastActiveChannel()
        if (channelId == null) return

        currentStreamJob = serviceScope.launch {
            chatRepository.eventStream(channelId)
                .catch { e -> Log.e("Service", "Stream error", e) }
                .collect { event ->
                    // Only show notification when an event (new message) is received
                    // and the app is not in the foreground on this channel.
                    if (!ChatApplication.AppState.isInForeground || activeChannelId != channelId) {
                        when (event) {
                            is ChatEvent.SendMessage -> notificationService.showMessageNotification(
                                conversationId = channelId.toString(),
                                senderName = event.data.display_name,
                                messagePreview = event.data.text
                            )
                            else -> {}
                        }
                    }
                }
        }
    }

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onDestroy() {
        super.onDestroy()
        instance = null
        serviceScope.cancel()
    }
}
