package chat.pyramid.pyramid

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.RemoteInput

object NotificationHelper {
    const val CHANNEL_ID = "pyramid_messages"

    /** Deterministic notification ID — same algorithm as Dart's _stableRoomId. */
    fun stableId(roomId: String): Int {
        var h = 0
        for (c in roomId) h = ((h * 31) + c.code) and 0x7FFFFFFF
        return if (h == 0) 1 else h
    }

    fun ensureChannel(context: Context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID, "Nachrichten", NotificationManager.IMPORTANCE_HIGH
            ).apply {
                description = "Neue Nachrichten"
                enableVibration(true)
            }
            nm(context).createNotificationChannel(channel)
        }
    }

    fun show(context: Context, title: String, body: String, roomId: String, notifId: Int) {
        ensureChannel(context)

        val mutFlag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
            PendingIntent.FLAG_MUTABLE else 0

        // Reply action — BroadcastReceiver so replying NEVER opens the app.
        // ReplyReceiver decrypts/sends via the background engine when killed.
        // (ReplyReceiver has multiple RemoteInput key fallbacks for OEM quirks.)
        val replyInput = RemoteInput.Builder(ReplyReceiver.REMOTE_INPUT_KEY)
            .setLabel("Antworten…").build()
        val replyIntent = Intent(context, ReplyReceiver::class.java).apply {
            action = ReplyReceiver.ACTION_REPLY
            putExtra(ReplyReceiver.EXTRA_ROOM_ID, roomId)
            putExtra(ReplyReceiver.EXTRA_NOTIF_ID, notifId)
        }
        val replyPi = PendingIntent.getBroadcast(
            context, notifId,
            replyIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or mutFlag,
        )
        val replyAction = NotificationCompat.Action.Builder(0, "Antworten", replyPi)
            .addRemoteInput(replyInput)
            .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
            .build()

        // Dismiss action — also points to ReplyReceiver so notification is cancelled.
        val dismissIntent = Intent(context, ReplyReceiver::class.java).apply {
            action = ReplyReceiver.ACTION_DISMISS
            putExtra(ReplyReceiver.EXTRA_ROOM_ID, roomId)
            putExtra(ReplyReceiver.EXTRA_NOTIF_ID, notifId)
        }
        val dismissPi = PendingIntent.getBroadcast(
            context, notifId + 1_000_000,
            dismissIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
        )

        // Tap action — opens MainActivity to the right room.
        val tapIntent = Intent(context, MainActivity::class.java).apply {
            action = Intent.ACTION_MAIN
            addCategory(Intent.CATEGORY_LAUNCHER)
            putExtra("room_id", roomId)
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP
        }
        val tapPi = PendingIntent.getActivity(
            context, notifId + 2_000_000,
            tapIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or mutFlag,
        )

        val notif = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_notification)
            .setColor(Color.rgb(0x7B, 0x61, 0xFF))
            .setContentTitle(title)
            .setContentText(body)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            // Only buzz/heads-up on the first show — the decrypted update reuses
            // the same notifId and replaces the text silently (no second alert).
            .setOnlyAlertOnce(true)
            .setContentIntent(tapPi)
            .setAutoCancel(true)
            .addAction(replyAction)
            .addAction(NotificationCompat.Action(0, "Gelesen", dismissPi))
            .setGroup(CHANNEL_ID)
            .build()

        nm(context).notify(notifId, notif)
    }

    private fun nm(context: Context) =
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
