package com.app.simplitend.locationupdates;

import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_REQUEST_TAG;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

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.Priority;

public class DefaultLocationClient implements LocationClient{

    private final Context context;
    private final FusedLocationProviderClient fusedLocationProviderClient;

    private LocationRequest locationRequest;
    private LocationCallback locationCallback;

    public DefaultLocationClient(Context context, FusedLocationProviderClient fusedLocationProviderClient) {
        this.context = context;
        this.fusedLocationProviderClient = fusedLocationProviderClient;
    }

    @Override
    public void getLocationUpdates(long interval, @NonNull DefaultLocationUpdates defaultLocationUpdates) throws LocationException {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Log.e(LOCATION_REQUEST_TAG, "getLocationUpdates: NO LOCATION PERMISSION");
            throw new LocationException("NO LOCATION PERMISSION FROM USER");
        }

        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!isGpsEnabled && !isNetworkEnabled) {
            LocationException locationException = new LocationException("GPS is off");
            Log.e(LOCATION_REQUEST_TAG, "getLocationUpdates: ", locationException);
            throw locationException;
        }

        locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
                .setMinUpdateDistanceMeters(100) // receive updates only if user has moved over 100 meters
                .build();

         locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                super.onLocationResult(locationResult);
                Location location;
                if (locationResult.getLocations().isEmpty()) {
                    location = null;
                } else {
                    location = locationResult.getLocations().get(locationResult.getLocations().size() - 1);
                }

                defaultLocationUpdates.locationUpdates(location);
            }
        };

        fusedLocationProviderClient.requestLocationUpdates(locationRequest,
                locationCallback, Looper.getMainLooper());
        Log.d(LOCATION_REQUEST_TAG, "getLocationUpdates: RECEIVING LOCATION UPDATES AT EVERY " + interval + " millis");
    }

    public void removeLocationUpdates(){
        if (locationRequest != null && fusedLocationProviderClient != null && locationCallback != null){
            fusedLocationProviderClient.removeLocationUpdates(locationCallback)
                    .addOnCompleteListener(task -> {
                        if (task.isSuccessful()) {
                            Log.v(LOCATION_REQUEST_TAG, "onComplete: LOCATION UPDATES REMOVED");
                        }
                    });
        }
    }
}
