package com.lemenzo.messenger.notifications;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Person;
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import com.lemenzo.messenger.ConversationActivity;
import com.lemenzo.messenger.R;

public final class MessageNotificationManager {
    public static final String CHANNEL = "lemenzo_messages";
    public static final String REMOTE_INPUT_KEY = "lemenzo_reply_text";

    private MessageNotificationManager() {}

    public static void ensureChannel(Context c) {
        NotificationManager nm = c.getSystemService(NotificationManager.class);
        if (nm == null) return;

        NotificationChannel channel = new NotificationChannel(
                CHANNEL,
                c.getString(R.string.notification_channel_messages),
                NotificationManager.IMPORTANCE_HIGH);
        channel.enableVibration(true);
        nm.createNotificationChannel(channel);
    }

    public static void notifyIncoming(
            Context c,
            long threadId,
            String address,
            int subscriptionId,
            String title,
            String body,
            int id) {
        if (c.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS)
                != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        ensureChannel(c);

        Intent launch = new Intent(c, ConversationActivity.class)
                .putExtra("thread_id", threadId)
                .putExtra("address", address)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

        PendingIntent content = PendingIntent.getActivity(
                c,
                id,
                launch,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

        Intent readIntent = new Intent(c, NotificationActionReceiver.class)
                .setAction(NotificationActionReceiver.ACTION_MARK_READ)
                .putExtra("thread_id", threadId)
                .putExtra("notification_id", id);

        PendingIntent markRead = PendingIntent.getBroadcast(
                c,
                id + 100000,
                readIntent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

        RemoteInput remoteInput = new RemoteInput.Builder(REMOTE_INPUT_KEY)
                .setLabel(c.getString(R.string.reply))
                .build();

        Intent replyIntent = new Intent(c, NotificationActionReceiver.class)
                .setAction(NotificationActionReceiver.ACTION_REPLY)
                .putExtra("thread_id", threadId)
                .putExtra("address", address)
                .putExtra("subscription_id", subscriptionId)
                .putExtra("notification_id", id);

        PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
                c,
                id + 200000,
                replyIntent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);

        Notification.Action replyAction = new Notification.Action.Builder(
                null,
                c.getString(R.string.reply),
                replyPendingIntent)
                .addRemoteInput(remoteInput)
                .setAllowGeneratedReplies(true)
                .build();

        Notification.Action markReadAction = new Notification.Action.Builder(
                null,
                c.getString(R.string.mark_read),
                markRead)
                .build();

        // Keep the real SMS content in the private notification so Android's
        // notification pipeline (including Message Wipe Protection) can inspect
        // the same MessagingStyle payload used by other messaging apps.
        Person localUser = new Person.Builder()
                .setName(c.getString(R.string.app_name))
                .build();
        Person sender = new Person.Builder()
                .setName(title)
                .build();

        Notification.MessagingStyle messagingStyle =
                new Notification.MessagingStyle(localUser)
                        .addMessage(body, System.currentTimeMillis(), sender);

        // Android/SystemUI uses this redacted public version whenever sensitive
        // lock-screen content is hidden. It deliberately contains neither the
        // sender nor the SMS body.
        Notification publicVersion = new Notification.Builder(c, CHANNEL)
                .setSmallIcon(R.drawable.ic_notification_message)
                .setColor(c.getColor(R.color.lemenzo_blue))
                .setContentTitle(c.getString(R.string.new_message_private))
                .setContentText(c.getString(R.string.new_message_private_summary))
                .setCategory(Notification.CATEGORY_MESSAGE)
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .build();

        Notification notification = new Notification.Builder(c, CHANNEL)
                .setSmallIcon(R.drawable.ic_notification_message)
                .setColor(c.getColor(R.color.lemenzo_blue))
                .setContentTitle(title)
                .setContentText(body)
                .setStyle(messagingStyle)
                .setVisibility(Notification.VISIBILITY_PRIVATE)
                .setPublicVersion(publicVersion)
                .setAutoCancel(true)
                .setCategory(Notification.CATEGORY_MESSAGE)
                .setContentIntent(content)
                .addAction(replyAction)
                .addAction(markReadAction)
                .build();

        NotificationManager nm = c.getSystemService(NotificationManager.class);
        if (nm != null) {
            try {
                nm.notify(id, notification);
            } catch (SecurityException ignored) {
            }
        }
    }
    public static void notifyMmsDownloadFailed(Context c, String token) {
        if (c.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS)
                != PackageManager.PERMISSION_GRANTED) return;
        ensureChannel(c);
        int id = mmsFailureId(token);
        Intent retry = new Intent(c, NotificationActionReceiver.class)
                .setAction(NotificationActionReceiver.ACTION_RETRY_MMS_DOWNLOAD)
                .putExtra("download_token", token)
                .putExtra("notification_id", id);
        PendingIntent retryPending = PendingIntent.getBroadcast(c, id, retry,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        Notification notification = new Notification.Builder(c, CHANNEL)
                .setSmallIcon(R.drawable.ic_notification_message)
                .setColor(c.getColor(R.color.lemenzo_blue))
                .setContentTitle(c.getString(R.string.mms_download_failed))
                .setContentText(c.getString(R.string.mms_download_retry_summary))
                .setCategory(Notification.CATEGORY_ERROR)
                .setAutoCancel(false)
                .addAction(new Notification.Action.Builder(null,
                        c.getString(R.string.retry_message), retryPending).build())
                .build();
        NotificationManager nm = c.getSystemService(NotificationManager.class);
        if (nm != null) nm.notify(id, notification);
    }

    public static void cancelMmsDownloadFailure(Context c, String token) {
        NotificationManager nm = c.getSystemService(NotificationManager.class);
        if (nm != null) nm.cancel(mmsFailureId(token));
    }

    private static int mmsFailureId(String token) {
        return 0x4d4d0000 ^ (token == null ? 0 : token.hashCode());
    }

}
