package com.p3.bewoplaner.data.firebase;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import com.p3.bewoplaner.R;
import com.p3.bewoplaner.data.AppPrefsConstants;
import com.p3.bewoplaner.data.prefs.LongPreference;
import com.p3.bewoplaner.data.repository.GroupRealmRepository;
import com.p3.bewoplaner.data.repository.MessageRealmRepository;
import com.p3.bewoplaner.data.repository.specifications.GroupByIdSpecification;
import com.p3.bewoplaner.data.repository.specifications.MessageByIdSpecification;
import com.p3.bewoplaner.di.InjectionHelper;
import com.p3.bewoplaner.model.Group;
import com.p3.bewoplaner.model.Message;
import com.p3.bewoplaner.page.main.MainActivity;
import com.p3.bewoplaner.utils.Constants;
import com.p3.bewoplaner.utils.LoggedOutUtils;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput;
import android.support.v4.content.ContextCompat;

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import static android.graphics.BitmapFactory.decodeStream;
import static com.p3.bewoplaner.utils.Constants.CHAT_IS_ALREADY_OPEN;

/**
 * Created by laszloffiferenc on 3/1/17.
 */
public class HandleMessagesService extends FirebaseMessagingService {

    @Inject
    MessageRealmRepository mMessageRealmRepository;

    @Inject
    GroupRealmRepository mGroupRealmRepository;

    @Inject
    @Named(AppPrefsConstants.USER_ID)
    LongPreference mUserIdReference;

    @Inject
    LoggedOutUtils mLoggedOutUtils;

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        InjectionHelper.getMessagingComponent(this).inject(HandleMessagesService.this);
        if (mLoggedOutUtils.checkLoggedOutPrefs()) {
            return;
        }
        customizeNotification(remoteMessage.getData());
    }

    private static Bitmap getBitmapFromUrl(String pictureUrl) {
        try {
            URL url = new URL(pictureUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            Bitmap bitmap = decodeStream(connection.getInputStream());
            return Bitmap.createScaledBitmap(bitmap, 240, 240, false);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private void customizeNotification(Map<String, String> data) {
        Bundle bundle = new Bundle();
        bundle.putString(Constants.MESSAGE_ID, data.get(Constants.MESSAGE_ID));
        bundle.putLong(Constants.GROUP_ID, Long.parseLong(data.get(Constants.GROUP_ID)));
        bundle.putLong(Constants.CREATED_AT, Long.parseLong(data.get(Constants.CREATED_AT)));
        bundle.putString(Constants.MESSAGE_TEXT, data.get(Constants.MESSAGE_TEXT));
        bundle.putString(Constants.FILE, data.get(Constants.FILE));
        bundle.putString(Constants.SMALLER_IMAGE, data.get(Constants.SMALLER_IMAGE));
        bundle.putString(Constants.FILENAME, data.get(Constants.FILENAME));
        bundle.putLong(Constants.USER_ID, Long.parseLong(data.get(Constants.USER_ID)));
        bundle.putString(Constants.USERNAME, data.get(Constants.USERNAME));
        bundle.putString(Constants.USER_AVATAR, data.get(Constants.USER_AVATAR));

        final Bitmap bitmap = getBitmapFromUrl(data.get(Constants.USER_AVATAR));
        Intent intent = new Intent();
        intent.putExtra(Constants.MESSAGE, bundle);
        intent.setAction(Constants.NOTIFICATION_BROADCAST);
        sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Bundle results = getResultExtras(true);

                if (!results.getBoolean(CHAT_IS_ALREADY_OPEN, false)) {
                    int groupId = (int) bundle.getLong(Constants.GROUP_ID);
                    int numberOfUsers = Integer.parseInt(data.get(Constants.GROUP_NR_USERS));
                    intent = MainActivity.createIntent(context, bundle, numberOfUsers, groupId);

                    PendingIntent pendingIntent = PendingIntent.getActivity(context,
                            groupId,
                            intent,
                            PendingIntent.FLAG_UPDATE_CURRENT);

                    NotificationCompat.Action action = createAction(context, numberOfUsers, groupId, bundle);

                    Bitmap bitmapToDisplay = bitmap;
                    if (bitmapToDisplay == null) {
                        bitmapToDisplay = BitmapFactory.decodeResource(context.getResources(), R.drawable.avatar);
                    }

                    NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                            .setSmallIcon(getNotificationIcon())
                            .setContentTitle(setNotificationTitle(data, numberOfUsers))
                            .setContentText(getTextFromNotification(data))
                            .setAutoCancel(true)
                            .setStyle(new NotificationCompat.BigTextStyle().bigText(getTextFromNotification(data)))
                            .setPriority(Notification.PRIORITY_MAX)
                            .setContentIntent(pendingIntent)
                            .setLargeIcon(getCircleBitmap(bitmapToDisplay))
                            .setGroup(String.valueOf(groupId))
                            .setGroupSummary(true)
                            .setDefaults(Notification.DEFAULT_ALL)
                            .setColor(ContextCompat.getColor(context, R.color.colorDefaultBright));

                    if (action != null) {
                        builder.addAction(action);
                    }

                    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                    notificationManager.notify(groupId, builder.build());

                    Message message = new Message(bundle.getString(Constants.MESSAGE_ID),
                            groupId,
                            bundle.getLong(Constants.CREATED_AT),
                            bundle.getString(Constants.MESSAGE_TEXT),
                            bundle.getString(Constants.FILE),
                            bundle.getString(Constants.SMALLER_IMAGE),
                            bundle.getString(Constants.FILENAME),
                            null,
                            bundle.getLong(Constants.USER_ID),
                            bundle.getString(Constants.USERNAME),
                            bundle.getString(Constants.USER_AVATAR),
                            Message.Status.DELIVERED,
                            false,
                            mUserIdReference.get(),
                            false);
                    storeMessageLocally(message);
                    storeGroupLocally(groupId, message);
                }
            }
        }, null, Activity.RESULT_OK, null, null);
    }

    private Bitmap getCircleBitmap(Bitmap bitmap) {
        final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(output);

        final int color = Color.RED;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawOval(rectF, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        bitmap.recycle();

        return output;
    }

    private void storeGroupLocally(long groupId, Message message) {
        Group group = new Group();
        group.id = groupId;
        group.lastMessage = message;
        mGroupRealmRepository.updateGroupMessage(group, new GroupByIdSpecification(mUserIdReference.get())).subscribe();
    }

    private void storeMessageLocally(Message message) {
        MessageByIdSpecification messageByIdSpecification = new MessageByIdSpecification(mUserIdReference.get());
        messageByIdSpecification.setMessageId(message.id);
        mMessageRealmRepository.update(Collections.singletonList(message), messageByIdSpecification)
                .subscribe();
    }

    private String setNotificationTitle(Map<String, String> data, int numberOfUsers) {
        if (numberOfUsers > 2) {
            return String.valueOf(data.get(Constants.USERNAME) + " @ " + data.get(Constants.GROUP_NAME));
        } else {
            return String.valueOf(data.get(Constants.USERNAME));
        }
    }

    private NotificationCompat.Action createAction(Context context, int noOfUsers, int groupId, Bundle bundle) {

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            return null;
        }
        Intent replyIntent = ReplyNotificationReceiver.createReplyIntent(context, bundle, noOfUsers, groupId);

        PendingIntent replyPendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                groupId,
                replyIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        String replyLabel = getResources().getString(R.string.chat_reply_label);
        RemoteInput remoteInput = new RemoteInput.Builder(Constants.KEY_TEXT_REPLY)
                .setLabel(replyLabel)
                .build();

        return new NotificationCompat.Action.Builder(R.drawable.send_enabled,
                getString(R.string.chat_reply_label), replyPendingIntent)
                .addRemoteInput(remoteInput)
                .build();
    }

    private String getTextFromNotification(Map<String, String> data) {
        String message = null;
        if (data.get(Constants.MESSAGE_TEXT) != null) {
            message = String.valueOf(data.get(Constants.MESSAGE_TEXT));
        }
        if (!data.get(Constants.FILE).equals("")) {
            message = getString(R.string.chat_file_received);
        }
        return message;
    }

    public static int getNotificationIcon() {
        boolean useWhiteIcon = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP);
        return useWhiteIcon ? R.drawable.icon_notification_transparent : R.drawable.notification_color;
    }

    public static CharSequence getReplyMessage(Intent intent) {
        Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
        if (remoteInput != null) {
            return remoteInput.getCharSequence(Constants.KEY_TEXT_REPLY);
        }
        return null;
    }
}
