package com.seatel.mobilehall.util;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ResolvableApiException;
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 com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.location.SettingsClient;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;

public class LocationRequestController {

    private final long UPDATE_INTERVAL = 2000;  /* 2 secs */
    private final long FASTEST_INTERVAL = 2000; /* 2 secs */
    private final int REQUEST_FINE_LOCATION = 123;
    private LocationUpdaterInterface mLocationUpdaterInterface;
    private final FusedLocationProviderClient fusedLocationProviderClient;
    private final Context mContext;
    private Activity mActivity;
    private LocationCallback locationListener;

    public LocationRequestController(Context mContext) {

        this.mContext = mContext;
        if (mContext instanceof Activity) this.mActivity = (Activity) mContext;
        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(mContext);
    }

    @SuppressLint("RestrictedApi")
    private void startLocationUpdates(int priority) {

        // Create the location request to start receiving updates
        LocationRequest mLocationRequest = new LocationRequest();
        mLocationRequest.setPriority(priority);
        mLocationRequest.setInterval(UPDATE_INTERVAL);
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

        if (mActivity != null) {

            // Create LocationSettingsRequest object using location request
            LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
            builder.addLocationRequest(mLocationRequest);
            builder.setAlwaysShow(true);
            LocationSettingsRequest locationSettingsRequest = builder.build();

            Task<LocationSettingsResponse> result =
                    LocationServices.getSettingsClient(mContext).checkLocationSettings(locationSettingsRequest);


            result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
                @Override
                public void onComplete(@NonNull Task<LocationSettingsResponse> task) {

                    try {
                        task.getResult(ApiException.class);
                    } catch (ApiException ex) {
                        switch (ex.getStatusCode()) {
                            case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                                try {
                                    ResolvableApiException resolvableApiException = (ResolvableApiException) ex;
                                    resolvableApiException.startResolutionForResult(mActivity, 123);
                                } catch (IntentSender.SendIntentException e) {
                                    e.printStackTrace();
                                }
                                break;
                        }
                    }
                }
            });

            // Check whether location settings are satisfied
            // https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
            SettingsClient settingsClient = LocationServices.getSettingsClient(mContext);
            settingsClient.checkLocationSettings(locationSettingsRequest);
        }


        // new Google API SDK v11 uses getFusedLocationProviderClient(this)

        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) !=
                PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        locationListener = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                onLocationChanged(locationResult.getLastLocation());
            }
        };
        fusedLocationProviderClient.requestLocationUpdates(mLocationRequest, locationListener, Looper.myLooper());
    }

    public void onLocationChanged(Location location) {

        if (mLocationUpdaterInterface != null && location != null) {
            mLocationUpdaterInterface.onLocationCallBack("location", location);
        }
    }

    public void removeLocationUpdate() {

        try {
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) !=
                    PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) !=
                            PackageManager.PERMISSION_GRANTED) {
                return;
            }

            fusedLocationProviderClient.removeLocationUpdates(locationListener);
            mLocationUpdaterInterface = null;

        } catch (Exception ex) {
            Log.d("On Remove", "fail to remove location listener, ignore", ex);
        }

    }

    public void checkPermissions() {
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)
            requestPermissions();
        else
            startLocationUpdates(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    private void requestPermissions() {
        ActivityCompat.requestPermissions(mActivity,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
    }

    public void checkPermissions(Fragment fragment) {
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(fragment);
        }
    }

    private void requestPermissions(Fragment fragment) {
        fragment.requestPermissions(
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
    }

    private void getLastLocation() {

        // Get last known recent location using new Google Play Services SDK (v11+)
        if (ActivityCompat.checkSelfPermission(mContext,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
            return;

        fusedLocationProviderClient.getLastLocation()
                .addOnSuccessListener(new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        // GPS location can be null if GPS is switched off
                        if (location != null) {
//                            onLocationChanged(location);
                            if (mLocationUpdaterInterface != null)
                                mLocationUpdaterInterface.onLocationCallBack("LastLocation", location);

                        }
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        e.printStackTrace();
                    }
                });
    }

    public void onPermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if (grantResults[0] == PackageManager.PERMISSION_GRANTED
                && requestCode == REQUEST_FINE_LOCATION) {
            startLocationUpdates(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
    }

    public void setLocationUpdateListener(LocationUpdaterInterface updateLocationListener) {
        mLocationUpdaterInterface = updateLocationListener;
    }

    public interface LocationUpdaterInterface {

        void onLocationCallBack(Object type, Location location);
    }
}
