package com.app.simplitend.apputils;

import static android.content.Context.NOTIFICATION_SERVICE;
import static com.app.simplitend.apputils.AppUtil.NOTIFICATION_ACTION;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_ID;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;

import android.Manifest;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.app.simplitend.patientgeofencing.GeoFenceHelper;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.model.LatLng;
import com.onesignal.OneSignal;
import com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class NotificationService implements INotificationServiceExtension {

    public static final String CONTENT_TYPE_KEY = "content_type_key";
    public static final String NOTIFICATION_BODY_KEY = "notification_body_key";
    public static final String NOTIFICATION_TITLE_KEY = "notification_title_key";
    public static final String NOTIFICATION_CONTENT_ID_KEY = "notification_title_key";

    public static final String NOTIFICATION_SENIOR_ADDRESS_KEY = "notification_senior_address";

    @Override
    public void onNotificationReceived(@NonNull INotificationReceivedEvent iNotificationReceivedEvent) {
//        Log.d("aditya testing", "onNotificationReceived: " + iNotificationReceivedEvent.getNotification());

        // showing maximum 7 notifications due to the limitations enforced by manufacturers
        // Thus, removing the oldest notification to show this new notification

        NotificationManager notificationManager = (NotificationManager) iNotificationReceivedEvent.getContext().getSystemService(NOTIFICATION_SERVICE);
        try {
            int active_notifications_count = notificationManager.getActiveNotifications().length;
            if (active_notifications_count >= 7) // already number is incremented when notification is arrived
            {
                List<StatusBarNotification> active_notifications = Arrays.asList(notificationManager.getActiveNotifications());
                active_notifications.sort(Comparator.comparingInt(n -> (int) n.getPostTime()));

                // removing last item
                StatusBarNotification notification = active_notifications.get(active_notifications.size() - 1);
                OneSignal.getNotifications().removeNotification(notification.getId());
            }
        } catch (Exception e) {
            // clearing all notifications
            OneSignal.getNotifications().clearAllNotifications();
        }

        JSONObject extras = iNotificationReceivedEvent.getNotification().getAdditionalData();
        String content_type = null, senior_current_address = null;
        int id = -1;
        if (extras != null) {
            try {
                content_type = extras.getString("content_type");
                id = extras.getInt("id");
            } catch (JSONException e) {
                // do nothing
            }

            try {
                senior_current_address = extras.getString("address");
            } catch (JSONException e) {
                // do nothing
            }
        }

        if (Constants.CHATS_NOTIFICATIONS.equals(content_type)){
            // chat notifications doesn't need to be handled for bottom sheet
            // or broadcasts
            return;
        }

        Intent intent = new Intent(iNotificationReceivedEvent.getContext(), BottomNotificationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(NOTIFICATION_ACTION);
        intent.putExtra(CONTENT_TYPE_KEY, content_type);
        intent.putExtra(NOTIFICATION_BODY_KEY, iNotificationReceivedEvent.getNotification().getBody());
        intent.putExtra(NOTIFICATION_TITLE_KEY, iNotificationReceivedEvent.getNotification().getTitle());
        intent.putExtra(NOTIFICATION_CONTENT_ID_KEY, id);
        intent.putExtra(NOTIFICATION_SENIOR_ADDRESS_KEY, senior_current_address);

        try {
            if (AppUtil.getCgToken(iNotificationReceivedEvent.getContext()) != null){
                // only if caregiver is logged in
                iNotificationReceivedEvent.getContext().startActivity(intent);
            }
        } catch (Exception e) {
            // do nothing
        }

        Intent broadcastIntent = new Intent(NOTIFICATION_ACTION);
        broadcastIntent.putExtra(CONTENT_TYPE_KEY, content_type);
        broadcastIntent.putExtra(NOTIFICATION_BODY_KEY, iNotificationReceivedEvent.getNotification().getBody());
        broadcastIntent.putExtra(NOTIFICATION_TITLE_KEY, iNotificationReceivedEvent.getNotification().getTitle());
        broadcastIntent.putExtra(NOTIFICATION_CONTENT_ID_KEY, id);
        broadcastIntent.putExtra(NOTIFICATION_SENIOR_ADDRESS_KEY, senior_current_address);

        iNotificationReceivedEvent.getContext().sendBroadcast(broadcastIntent);

        if (Constants.GEOFENCING_RADIUS_ADDED.equals(content_type)
                || Constants.GEOFENCING_RADIUS_UPDATED.equals(content_type)
                || Constants.HOME_LOCATION_UPDATED.equals(content_type)) {

            if (AppUtil.isPatientLoggedIn(iNotificationReceivedEvent.getContext())){
                // Either Geofence radius or Patient's location has changed.
                Log.d(GEOFENCE_TAG, "Adding geo fence...");
                if (ActivityCompat.checkSelfPermission(iNotificationReceivedEvent.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    Log.d(GEOFENCE_TAG, "No location permission");
                    return;
                }

                try {
                    double lat = extras.getDouble("lat");
                    double lng = extras.getDouble("lng");
                    double radius = extras.getDouble("radius");
                    String message;
                    try {
                        message = extras.getString("message");
                    } catch (JSONException e) {
                        message = null;
                    }

                    Log.d(GEOFENCE_TAG, "DATA RECEIVED WITH NOTIFICATION : Lat/Lng: " + lat + "," + lng + " Radius: " + radius);

                    if (radius >= 0){
                        addGeoFence(new LatLng(lat, lng),
                                radius, message, iNotificationReceivedEvent.getContext());
                    }
                }catch (Exception e){
                    Log.e(GEOFENCE_TAG, "COULDN'T CREATE GEOFENCE: " + e);
                    Log.e(GEOFENCE_TAG, "EXTRAS FROM NOTIFICATION: " + extras);
                }
            }else{
                Log.d(GEOFENCE_TAG, "onNotificationReceived of PATIENT GEOFENCE CHANGED. BUT PATIENT IS LOGGED OUT.");
            }
        }
    }

    @RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
    private void addGeoFence(@NonNull LatLng latLng, double GEOFENCING_RADIUS, String message, Context context) {
        AppUtil.removeGeofence(context);

        GeoFenceHelper geoFenceHelper = new GeoFenceHelper(context);
        GeofencingClient geofencingClient = LocationServices.getGeofencingClient(context);

        // checking for background location updates for API level 29 and above
        if (Build.VERSION.SDK_INT >= 29) {
            if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Log.d(GEOFENCE_TAG, "addGeoFence: No background location permission");
                return;
            }
        }

        Geofence geofence = geoFenceHelper.getGeoFence(GEOFENCE_ID, latLng, (float) GEOFENCING_RADIUS,
                Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT);
        GeofencingRequest geofencingRequest = geoFenceHelper.getGeoFencingRequest(geofence);
        PendingIntent pendingIntent = geoFenceHelper.getPendingIntent();

        geofencingClient.addGeofences(geofencingRequest, pendingIntent)
                .addOnSuccessListener(aVoid -> {
                    Log.d(GEOFENCE_TAG, "Geofence added successfully.");
                    AppUtil.updatePatientGeofence(context, latLng.latitude+"", latLng.longitude+"",
                            GEOFENCING_RADIUS+"", "kms", message);
                })
                .addOnFailureListener(e -> Log.d(GEOFENCE_TAG, "onFailure: Geofence couldn't be added: " + e.getLocalizedMessage()  + " " + latLng + " Radius: " + GEOFENCING_RADIUS));

    }
}
