package top.yeij.cyrene.service

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import org.koin.core.context.GlobalContext
import top.yeij.cyrene.data.local.PreferencesDataStore
import top.yeij.cyrene.data.repository.ChatRepositoryImpl
import top.yeij.cyrene.util.RuntimeLog

class KeepAliveReceiver : BroadcastReceiver() {

    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "Keep-alive alarm fired")
        RuntimeLog.notify("keepalive", "Alarm fired in background")

        scope.launch {
            try {
                val prefs: PreferencesDataStore = GlobalContext.get().get()
                val token = prefs.token.firstOrNull()
                if (token.isNullOrBlank()) {
                    Log.d(TAG, "No auth token, skipping wake-up")
                    RuntimeLog.notify("keepalive", "Skipping: no auth token")
                    return@launch
                }

                if (!WebSocketKeepAliveService.isRunning) {
                    WebSocketKeepAliveService.start(context)
                    RuntimeLog.notify("keepalive", "Foreground service restarted")
                }

                val repo: ChatRepositoryImpl = GlobalContext.get().get()
                val wasConnected = repo.connectionState.value
                repo.ensureConnected()
                RuntimeLog.notify("keepalive", "WS reconnect triggered: wasConnected=$wasConnected nowConnected=${repo.connectionState.value}")

                schedule(context)
            } catch (e: Throwable) {
                Log.e(TAG, "Keep-alive check failed: ${e.message}", e)
                RuntimeLog.notify("keepalive", "Failed: ${e.message}")
                schedule(context)
            }
        }
    }

    companion object {
        private const val TAG = "CyreneKeepAlive"

        const val INTERVAL_MS = 5 * 60 * 1000L // 5 minutes

        fun schedule(context: Context) {
            try {
                val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
                val intent = Intent(context, KeepAliveReceiver::class.java)
                val pendingIntent = PendingIntent.getBroadcast(
                    context, 0, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
                )

                // Cancel existing alarm first
                alarmManager.cancel(pendingIntent)

                val triggerAt = System.currentTimeMillis() + INTERVAL_MS
                if (alarmManager.canScheduleExactAlarms()) {
                    alarmManager.setExactAndAllowWhileIdle(
                        AlarmManager.RTC_WAKEUP, triggerAt, pendingIntent
                    )
                } else {
                    alarmManager.setAndAllowWhileIdle(
                        AlarmManager.RTC_WAKEUP, triggerAt, pendingIntent
                    )
                }
            } catch (e: Exception) {
                Log.e(TAG, "Failed to schedule keep-alive: ${e.message}")
            }
        }

        fun cancel(context: Context) {
            try {
                val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
                val intent = Intent(context, KeepAliveReceiver::class.java)
                val pendingIntent = PendingIntent.getBroadcast(
                    context, 0, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
                )
                alarmManager.cancel(pendingIntent)
            } catch (e: Exception) {
                Log.e(TAG, "Failed to cancel keep-alive: ${e.message}")
            }
        }
    }
}
