package com.anypreta.bountyboard.data.push

import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import com.anypreta.bountyboard.BountyBoardApp
import com.anypreta.bountyboard.ui.util.htmlToPlain
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch

/**
 * A started foreground service that keeps the live-update WebSocket connected even
 * after the app is swiped away, and raises system notifications for incoming alerts
 * and messages. This is what makes notifications work while the app is "closed"
 * (it does NOT survive an explicit Force-Stop or a reboot-until-reopened).
 */
class LiveSocketService : Service() {

    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
    private var started = false

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

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        startInForeground()
        if (!started) {
            started = true
            val container = (application as BountyBoardApp).container
            container.live.connect()

            scope.launch {
                container.live.notifications.collect { n ->
                    if (!container.appForeground) {
                        PushNotifier.notifyAlert(
                            applicationContext,
                            id = ("a" + n.id).hashCode(),
                            title = n.title.ifBlank { "New alert" },
                            body = htmlToPlain(n.body).ifBlank { "You have a new alert." },
                            route = PushNotifier.routeForServerLink(n.link),
                        )
                    }
                }
            }
            scope.launch {
                container.live.chatMessages.collect { m ->
                    val mine = m.senderId == container.session.user.value?.id
                    if (!container.appForeground && !mine) {
                        PushNotifier.notifyMessage(
                            applicationContext,
                            id = ("m" + m.conversationId).hashCode(),
                            title = "New message",
                            body = htmlToPlain(m.body).ifBlank { "New message" },
                            route = "conversation/${m.conversationId}",
                        )
                    }
                }
            }
        }
        return START_STICKY
    }

    private fun startInForeground() {
        val notification = PushNotifier.serviceNotification(this)
        val type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
        } else {
            0
        }
        ServiceCompat.startForeground(this, PushNotifier.SERVICE_NOTIF_ID, notification, type)
    }

    // Keep running when the task is swiped away — that's the whole point.
    override fun onTaskRemoved(rootIntent: Intent?) {
        // no-op: stay alive
    }

    override fun onDestroy() {
        scope.cancel()
        started = false
        // The socket itself is owned by the process/UI; leave it for MainShell/logout.
        super.onDestroy()
    }

    companion object {
        fun start(context: Context) {
            val intent = Intent(context, LiveSocketService::class.java)
            ContextCompat.startForegroundService(context, intent)
        }

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