/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.core.push

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.runicgateway.app.MainActivity
import com.runicgateway.app.R
import dagger.hilt.android.qualifiers.ApplicationContext
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Builds the notification channels and posts a notification for a received tickle
 * (PLAN.md §11, M7 Part 2 work items 2/3/7). v1 shows a **generic per-stream**
 * notification titled from the fixed [PushStreams] catalog — the content-free tickle
 * carries nothing to render, so nothing is fetched to display the notification; tapping
 * deep-links into [MainActivity] (which fetches fresh over the authenticated API).
 */
@Singleton
class PushNotifier @Inject constructor(
    @param:ApplicationContext private val context: Context,
) {
    private val manager = NotificationManagerCompat.from(context)
    private val nextId = AtomicInteger(1)

    /** Create both channels; safe to call repeatedly (creation is idempotent). */
    fun ensureChannels() {
        val system = context.getSystemService(NotificationManager::class.java) ?: return
        system.createNotificationChannel(
            NotificationChannel(
                CHANNEL_MESSAGES,
                context.getString(R.string.push_channel_messages),
                NotificationManager.IMPORTANCE_DEFAULT,
            ).apply { description = context.getString(R.string.push_channel_messages_desc) },
        )
        system.createNotificationChannel(
            NotificationChannel(
                CHANNEL_SERVICE,
                context.getString(R.string.push_channel_service),
                NotificationManager.IMPORTANCE_LOW,
            ).apply {
                description = context.getString(R.string.push_channel_service_desc)
                setShowBadge(false)
            },
        )
    }

    /** The persistent low-importance notification the foreground service runs under. */
    fun serviceNotification(): Notification =
        NotificationCompat.Builder(context, CHANNEL_SERVICE)
            .setContentTitle(context.getString(R.string.push_service_title))
            .setContentText(context.getString(R.string.push_service_text))
            .setSmallIcon(R.drawable.ic_stat_name)
            .setOngoing(true)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setContentIntent(deepLinkIntent(stream = null, ref = null))
            .build()

    /** Post a notification for a tickle, deep-linking to the stream's screen on tap. */
    fun notify(tickle: PushTickle) {
        if (!manager.areNotificationsEnabled()) return // POST_NOTIFICATIONS not granted
        val title = context.getString(PushStreams.titleRes(tickle.stream))
        val notification = NotificationCompat.Builder(context, CHANNEL_MESSAGES)
            .setContentTitle(title)
            .setSmallIcon(R.drawable.ic_stat_name)
            .setAutoCancel(true)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(deepLinkIntent(tickle.stream, tickle.ref))
            .build()
        try {
            manager.notify(nextId.getAndIncrement(), notification)
        } catch (_: SecurityException) {
            // Racing a permission revoke — drop silently rather than crash.
        }
    }

    private fun deepLinkIntent(stream: String?, ref: String?): PendingIntent {
        val intent = Intent(context, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
            if (stream != null) putExtra(EXTRA_STREAM, stream)
            if (ref != null) putExtra(EXTRA_REF, ref)
        }
        // A distinct request code per stream so PendingIntents don't collapse into one.
        val requestCode = stream?.hashCode() ?: 0
        return PendingIntent.getActivity(
            context,
            requestCode,
            intent,
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
        )
    }

    companion object {
        const val CHANNEL_MESSAGES = "push_messages"
        const val CHANNEL_SERVICE = "push_service"

        /** Intent extras a tapped notification carries into [MainActivity] (§7 deep-links). */
        const val EXTRA_STREAM = "com.runicgateway.app.push.STREAM"
        const val EXTRA_REF = "com.runicgateway.app.push.REF"
    }
}
