package de.beyondsoft.ownchat.data.firebase;

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

import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.responses.MessageResponse;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.repository.GroupRealmRepository;
import de.beyondsoft.ownchat.data.repository.MessageRealmRepository;
import de.beyondsoft.ownchat.data.repository.specifications.GroupByIdSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.MessageByIdSpecification;
import de.beyondsoft.ownchat.di.InjectionHelper;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.main.MainActivity;
import de.beyondsoft.ownchat.utils.Constants;
import de.beyondsoft.ownchat.utils.LoggedOutUtils;
import de.beyondsoft.ownchat.utils.rx.RxUtils;
import rx.Observable;
import rx.functions.Func1;

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 android.text.TextUtils;

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 de.beyondsoft.ownchat.utils.Constants.CHAT_IS_ALREADY_OPEN;

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

    @Inject
    ChatService mChatService;

    @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> dataMap) {
        String messageId = dataMap.get(Constants.MESSAGE_ID);

        mChatService.getMessage(messageId)
                .compose(RxUtils.provideDefaultTransformer())
                .flatMap(new ErrorHandlingResponseConverter<>())
                .flatMap(new Func1<MessageResponse, Observable<Message>>() {
                    @Override
                    public Observable<Message> call(MessageResponse messageResponse) {
                        return Observable.just(messageResponse.response.message);
                    }
                })
                .subscribe(this::getMessageSuccess, this::getMessageError);
    }

    private void getMessageSuccess(Message message) {
        Bundle bundle = new Bundle();

        bundle.putString(Constants.MESSAGE_ID, message.id);
        bundle.putLong(Constants.GROUP_ID, message.groupId);
        bundle.putLong(Constants.CREATED_AT, message.createdAt);
        bundle.putString(Constants.MESSAGE_TEXT, message.message);
        bundle.putString(Constants.FILE, message.filePath);
        bundle.putString(Constants.SMALLER_IMAGE, message.smallerImage);
        bundle.putString(Constants.FILENAME, message.originalFilename);
        bundle.putLong(Constants.USER_ID, message.senderId);
        bundle.putString(Constants.USERNAME, message.senderName);
        bundle.putString(Constants.USER_AVATAR, message.senderAvatar);

        final Bitmap bitmap = getBitmapFromUrl(message.senderAvatar);
        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 = message.numberOfGroupUsers;
                    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(message, message.numberOfGroupUsers))
                            .setContentText(getTextFromNotification(message))
                            .setAutoCancel(true)
                            .setStyle(new NotificationCompat.BigTextStyle().bigText(getTextFromNotification(message)))
                            .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 void getMessageError(Throwable throwable) {
        throwable.printStackTrace();
    }

    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(Message message, int numberOfUsers) {
        if (numberOfUsers > 2) {
            return message.senderName + " @ " + message.groupName;
        } else {
            return message.senderName;
        }
    }

    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(Message message) {
        String text = null;

        if(message.message != null) {
            text = message.message;
        }

        if(!TextUtils.isEmpty(message.originalFilename)) {
            text = getString(R.string.chat_file_received);
        }

        return text;
    }

    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;
    }
}
