package co.chatsdk.core.base;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.os.Looper;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;

import java.util.List;

import co.chatsdk.core.R;
import co.chatsdk.core.session.ChatSDK;
import co.chatsdk.core.utils.DisposableList;
import co.chatsdk.core.utils.PermissionRequestHandler;
import io.reactivex.Observable;
import io.reactivex.Single;

/**
 * Created by Pepe on 01/25/19.
 */

public class LocationProvider {

    protected final FusedLocationProviderClient locationClient;
    protected final DisposableList disposableList = new DisposableList();

    protected Context context() {
        return ChatSDK.shared().context();
    }

    public LocationProvider() {
        locationClient = LocationServices.getFusedLocationProviderClient(context());
    }

    public Observable<Location> requestLocationUpdates(Activity activity, long interval, int distance) {
        return requestLocationUpdates(interval)
                .distinctUntilChanged((l1, l2) -> l1.distanceTo(l2) < distance);
    }

    public Observable<Location> requestLocationUpdates(Activity activity, long interval) {
        return PermissionRequestHandler.shared().requestLocationAccess(activity)
                .andThen(requestLocationUpdates(interval));
    }

    public Single<Location> getLastLocation(Activity activity) {
        return PermissionRequestHandler.shared().requestLocationAccess(activity)
                .andThen(getLastLocation());
    }

     @SuppressLint("MissingPermission")
    protected Observable<Location> requestLocationUpdates(long interval) {
        return Observable.create(observable -> {
            LocationRequest locationRequest = new LocationRequest();
            locationRequest.setInterval(interval * 1000);
            locationRequest.setFastestInterval(interval * 1000);
            locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
            LocationCallback locationCallback = new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    Location location = getMostAccurateLocation(locationResult.getLocations());
                    if (location != null) {
                        observable.onNext(location);
                    }
                }
            };
            locationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
        });
    }

    @SuppressLint("MissingPermission")
    protected Single<Location> getLastLocation() {
        return Single.create(single -> {
            locationClient.getLastLocation().addOnSuccessListener(location -> {
                if (location != null) {
                    single.onSuccess(location);
                } else {
                    single.onError(new Error(context().getResources().getString(R.string.location_is_null)));
                }
            }).addOnFailureListener(single::onError);
        });
    }

    public Location getMostAccurateLocation(List<Location> locations) {
        Location accurateLocation = null;
        for (Location location : locations) {
            if (location == null) continue;
            if (accurateLocation == null || location.getAccuracy() >= accurateLocation.getAccuracy()) {
                accurateLocation = location;
            }
        }
        return accurateLocation;
    }

    public void dispose() {
        disposableList.dispose();
    }

}

@@ -722,22 +722,279 @@
 activex.
-Single
+ObservableEmitter;%0Aimport io.reactivex.ObservableOnSubscribe;%0Aimport io.reactivex.Single;%0Aimport io.reactivex.SingleEmitter;%0Aimport io.reactivex.SingleOnSubscribe;%0Aimport io.reactivex.android.schedulers.AndroidSchedulers;%0Aimport io.reactivex.schedulers.Schedulers
 ;%0A%0A/**%0A 
@@ -2235,16 +2235,50 @@
 .create(
+(ObservableOnSubscribe%3CLocation%3E) 
 observab
@@ -3100,32 +3100,107 @@
 r());%0A        %7D)
+.subscribeOn(Schedulers.single()).observeOn(AndroidSchedulers.mainThread())
 ;%0A    %7D%0A%0A    @Su
@@ -3311,16 +3311,46 @@
 .create(
+(SingleOnSubscribe%3CLocation%3E) 
 single -
@@ -3345,32 +3345,36 @@
 n%3E) single -%3E %7B%0A
+    
             loca
@@ -3445,32 +3445,36 @@
                 
+ 
+   
 if (location != 
@@ -3473,32 +3473,36 @@
 tion != null) %7B%0A
+    
                 
@@ -3525,32 +3525,36 @@
 cess(location);%0A
+    
                 
@@ -3574,32 +3574,36 @@
                 
+    
 single.onError(n
@@ -3684,34 +3684,42 @@
                 
-%7D%0A
+    %7D%0A    
             %7D).a
@@ -3766,16 +3766,49 @@
       %7D)
+.subscribeOn(Schedulers.single())
 ;%0A    %7D%0A

Add subsribeOn and observeOn