package com.tt.honeyDue.notifications

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.tt.honeyDue.MainActivity
import com.tt.honeyDue.R
import com.tt.honeyDue.models.DeviceRegistrationRequest
import com.tt.honeyDue.network.ApiResult
import com.tt.honeyDue.network.NotificationApi
import com.tt.honeyDue.storage.TokenStorage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
 * New-generation FirebaseMessagingService built for iOS parity. Routes each
 * incoming FCM data-message to the correct [NotificationChannels] channel,
 * attaches a deep-link PendingIntent when present, and uses a hashed
 * messageId as the notification id so duplicate redeliveries replace (not
 * stack).
 *
 * This is the sole MESSAGING_EVENT handler after the deferred-cleanup pass:
 * the manifest no longer wires the legacy `MyFirebaseMessagingService`, and
 * [onNewToken] now carries the token-registration path that used to live
 * there (auth-token guard + device-id + platform="android").
 */
class FcmService : FirebaseMessagingService() {

    override fun onNewToken(token: String) {
        super.onNewToken(token)
        Log.d(TAG, "FCM token refreshed (len=${token.length})")

        // Store token locally so the rest of the app can find it on demand.
        getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
            .edit()
            .putString(KEY_FCM_TOKEN, token)
            .apply()

        // Register with backend only if the user is logged in. Log-only on
        // failure — FCM will re-invoke onNewToken on next rotation.
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val authToken = TokenStorage.getToken() ?: return@launch
                val deviceId = android.provider.Settings.Secure.getString(
                    applicationContext.contentResolver,
                    android.provider.Settings.Secure.ANDROID_ID
                )
                val request = DeviceRegistrationRequest(
                    deviceId = deviceId,
                    registrationId = token,
                    platform = "android",
                    name = android.os.Build.MODEL
                )
                when (val result = NotificationApi().registerDevice(authToken, request)) {
                    is ApiResult.Success ->
                        Log.d(TAG, "Device registered successfully with new token")
                    is ApiResult.Error ->
                        Log.e(TAG, "Failed to register device with new token: ${result.message}")
                    is ApiResult.Loading,
                    is ApiResult.Idle -> {
                        // These states shouldn't occur for direct API calls.
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "Error registering device with new token", e)
            }
        }
    }

    override fun onMessageReceived(message: RemoteMessage) {
        super.onMessageReceived(message)

        val payload = NotificationPayload.parse(message.data)
        if (payload == null) {
            Log.w(TAG, "Dropping malformed FCM payload (keys=${message.data.keys})")
            return
        }

        // Make sure channels exist — safe to call every time.
        NotificationChannels.ensureChannels(this)

        val channelId = NotificationChannels.channelIdForType(payload.type)
        val notification = buildNotification(payload, channelId, message.messageId)

        val notificationId = (message.messageId ?: payload.deepLink ?: payload.title)
            .hashCode()

        NotificationManagerCompat.from(this).apply {
            if (areNotificationsEnabled()) {
                notify(notificationId, notification)
            } else {
                Log.d(TAG, "Notifications disabled — skipping notify()")
            }
        }
    }

    private fun buildNotification(
        payload: NotificationPayload,
        channelId: String,
        messageId: String?
    ): android.app.Notification {
        val contentIntent = buildContentIntent(payload, messageId)
        val notificationId = (messageId ?: payload.deepLink ?: payload.title).hashCode()

        val builder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(payload.title.ifBlank { getString(R.string.app_name) })
            .setContentText(payload.body)
            .setStyle(NotificationCompat.BigTextStyle().bigText(payload.body))
            .setAutoCancel(true)
            .setContentIntent(contentIntent)
            .setPriority(priorityForChannel(channelId))

        addActionButtons(builder, payload, notificationId, messageId)

        return builder.build()
    }

    /**
     * Attach iOS-parity action buttons (`NotificationCategories.swift`) to
     * the [builder] based on [payload.type]:
     *
     *  - task_reminder / task_overdue → Complete, Snooze, Open
     *  - residence_invite            → Accept, Decline, Open
     *  - subscription                → no actions (matches iOS TASK_COMPLETED)
     *
     * All actions fan out to [NotificationActionReceiver] under the
     * `com.tt.honeyDue.notifications` package.
     */
    private fun addActionButtons(
        builder: NotificationCompat.Builder,
        payload: NotificationPayload,
        notificationId: Int,
        messageId: String?
    ) {
        val seed = (messageId ?: payload.deepLink ?: payload.title).hashCode()
        val extras: Map<String, Any?> = mapOf(
            NotificationActions.EXTRA_TASK_ID to payload.taskId,
            NotificationActions.EXTRA_RESIDENCE_ID to payload.residenceId,
            NotificationActions.EXTRA_NOTIFICATION_ID to notificationId,
            NotificationActions.EXTRA_TITLE to payload.title,
            NotificationActions.EXTRA_BODY to payload.body,
            NotificationActions.EXTRA_TYPE to payload.type,
            NotificationActions.EXTRA_DEEP_LINK to payload.deepLink
        )

        when (payload.type) {
            NotificationChannels.TASK_REMINDER,
            NotificationChannels.TASK_OVERDUE -> {
                if (payload.taskId != null) {
                    builder.addAction(
                        0,
                        getString(R.string.notif_action_complete),
                        NotificationActionReceiver.actionPendingIntent(
                            this, NotificationActions.COMPLETE, seed, extras
                        )
                    )
                    builder.addAction(
                        0,
                        getString(R.string.notif_action_snooze),
                        NotificationActionReceiver.actionPendingIntent(
                            this, NotificationActions.SNOOZE, seed, extras
                        )
                    )
                }
                builder.addAction(
                    0,
                    getString(R.string.notif_action_open),
                    NotificationActionReceiver.actionPendingIntent(
                        this, NotificationActions.OPEN, seed, extras
                    )
                )
            }
            NotificationChannels.RESIDENCE_INVITE -> {
                if (payload.residenceId != null) {
                    builder.addAction(
                        0,
                        getString(R.string.notif_action_accept),
                        NotificationActionReceiver.actionPendingIntent(
                            this, NotificationActions.ACCEPT_INVITE, seed, extras
                        )
                    )
                    builder.addAction(
                        0,
                        getString(R.string.notif_action_decline),
                        NotificationActionReceiver.actionPendingIntent(
                            this, NotificationActions.DECLINE_INVITE, seed, extras
                        )
                    )
                }
                builder.addAction(
                    0,
                    getString(R.string.notif_action_open),
                    NotificationActionReceiver.actionPendingIntent(
                        this, NotificationActions.OPEN, seed, extras
                    )
                )
            }
            else -> {
                // subscription + unknown: tap-to-open only. iOS parity.
            }
        }
    }

    private fun buildContentIntent(
        payload: NotificationPayload,
        messageId: String?
    ): PendingIntent {
        val intent = Intent(this, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
            // Deep-link → set data URI so the launcher activity can route from the
            // existing intent-filter for the honeydue:// scheme.
            payload.deepLink?.let { data = Uri.parse(it) }
            payload.taskId?.let { putExtra(EXTRA_TASK_ID, it) }
            payload.residenceId?.let { putExtra(EXTRA_RESIDENCE_ID, it) }
            putExtra(EXTRA_TYPE, payload.type)
        }

        val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        } else {
            PendingIntent.FLAG_UPDATE_CURRENT
        }
        val requestCode = (messageId ?: payload.deepLink ?: payload.title).hashCode()
        return PendingIntent.getActivity(this, requestCode, intent, flags)
    }

    private fun priorityForChannel(channelId: String): Int = when (channelId) {
        NotificationChannels.TASK_OVERDUE -> NotificationCompat.PRIORITY_HIGH
        NotificationChannels.SUBSCRIPTION -> NotificationCompat.PRIORITY_LOW
        else -> NotificationCompat.PRIORITY_DEFAULT
    }

    companion object {
        private const val TAG = "FcmService"
        const val EXTRA_TASK_ID = "fcm_task_id"
        const val EXTRA_RESIDENCE_ID = "fcm_residence_id"
        const val EXTRA_TYPE = "fcm_type"

        private const val PREFS_NAME = "honeydue_prefs"
        private const val KEY_FCM_TOKEN = "fcm_token"

        /** Compatibility helper — mirrors the old MyFirebaseMessagingService API. */
        fun getStoredToken(context: Context): String? =
            context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
                .getString(KEY_FCM_TOKEN, null)
    }
}
