/*
 *  Copyright (c) 2018  STMicroelectronics – All rights reserved
 *  The STMicroelectronics corporate logo is a trademark of STMicroelectronics
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *  - Redistributions of source code must retain the above copyright notice, this list of conditions
 *    and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *
 *  - Neither the name nor trademarks of STMicroelectronics International N.V. nor any other
 *    STMicroelectronics company nor the names of its contributors may be used to endorse or
 *    promote products derived from this software without specific prior written permission.
 *
 *  - All of the icons, pictures, logos and other images that are provided with the source code
 *    in a directory whose title begins with st_images may only be used for internal purposes and
 *    shall not be redistributed to any third party or modified in any way.
 *
 *  - Any redistributions in binary form shall not include the capability to display any of the
 *    icons, pictures, logos and other images that are provided with the source code in a directory
 *    whose title begins with st_images.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 *  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 *  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 *  OF SUCH DAMAGE.
 */

package com.st.BlueSTSDK.Utils;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.location.LocationManager;
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.snackbar.Snackbar;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AlertDialog;
import android.view.View;
import android.widget.Toast;

import com.st.BlueSTSDK.R;

public class BlePermissionHelper{
    /**
     * request id for the activity that will ask to the user to enable the bt
     */
    public static final int REQUEST_ENABLE_BT = 1;
    /**
     * request id for grant the location permission
     */
    public static final int REQUEST_LOCATION_ACCESS = 2;


    public interface BlePermissionAcquiredCallback{
        void onBlePermissionAcquired();
        void onBlePermissionDenied();
    }

    private final @NonNull Context mCtx;
    private final @Nullable
    FragmentActivity mActivity;
    private final @Nullable
    Fragment mFragment;

    /**
     * @param src fragment that will trigger the open of the file selector
     */
    public BlePermissionHelper(@NonNull Fragment src) {
        this.mFragment = src;
        this.mCtx = src.requireContext();
        this.mActivity=null;
    }

    public BlePermissionHelper(@NonNull FragmentActivity src) {
        this.mFragment = null;
        mActivity = src;
        mCtx = mActivity;
    }


    private Activity requireActivity(){
        if(mFragment!=null)
            return mFragment.requireActivity();
        if(mActivity!=null)
            return mActivity;
        throw new IllegalStateException("Fragment or activity must be != null");
    }

    private void requestPermissions(String[] permission, int requestCode){
        if(mFragment!=null)
            mFragment.requestPermissions(permission,requestCode);
        else if (mActivity!=null)
            ActivityCompat.requestPermissions(mActivity,permission,requestCode);
        else {
            throw new IllegalStateException("Fragment or activity must be != null");
        }
    }

    private void startActivityForResult(Intent request,int requestCode){
        if(mFragment!=null)
            mFragment.startActivityForResult(request,requestCode);
        else if (mActivity!=null)
            mActivity.startActivityForResult(request,requestCode);
        else {
            throw new IllegalStateException("Fragment or activity must be != null");
        }
    }

    /**
     * check that the bluetooth is enabled
     * @return true if the bluetooth is enable false if we ask to the user to enable it
     */
    private boolean enableBluetoothAdapter(){
        final BluetoothManager bluetoothManager =
                ContextCompat.getSystemService(mCtx,BluetoothManager.class);
        if(bluetoothManager==null)
            throw new IllegalStateException("Bluetooth adapter is needed by this app!");
        //the adapter is !=null since we request in the manifest to have the bt capability
        final BluetoothAdapter btAdapter = bluetoothManager.getAdapter();

        // Ensures Bluetooth is enabled on the device.  If Bluetooth is not currently enabled,
        // fire an intent to display a dialog asking the user to grant permission to enable it.
        if (!btAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
            return false;
        }else
            return true;
    }//enableBluetoothAdapter

    /**
     * check that the location service is enabled
     * @return true if the location service is enabled, false if we ask to the user to do it
     */
    private boolean enableLocationService(){
        final LocationManager lm =  ContextCompat.getSystemService(mCtx,LocationManager.class);
        if(lm == null)
            throw new IllegalStateException("Location manager adapter is needed by this app!");
        boolean providerEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) |
                lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        if(!providerEnabled) {
            Resources res = mCtx.getResources();
            // notify user
            final AlertDialog.Builder dialog = new AlertDialog.Builder(mCtx);
            dialog.setMessage(res.getString(R.string.EnablePositionService));
            dialog.setPositiveButton(res.getString(android.R.string.ok),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                            mCtx.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                            paramDialogInterface.cancel();
                        }
                    });
            dialog.setNegativeButton(res.getString(android.R.string.cancel),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                            paramDialogInterface.cancel();
                            Toast.makeText(mCtx,
                                    R.string.LocationNotEnabled,
                                    Toast.LENGTH_SHORT).show();
                        }//onClick
                    });
                    dialog.show();
        }//if
        return providerEnabled;
    }//enableLocationService

    /**
     * check to have the permission needed for start a bluetooth scanning
     * @return true if we have ti false if we ask for it
     */
    private boolean checkBlePermission(){
        if (ContextCompat.checkSelfPermission(mCtx,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(),
                    Manifest.permission.ACCESS_FINE_LOCATION)) {
                final AlertDialog.Builder dialog = new AlertDialog.Builder(mCtx);
                dialog.setMessage(mCtx.getString(R.string.LocationCoarseRationale));
                dialog.setPositiveButton(android.R.string.ok,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                                requestPermissions(
                                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                        REQUEST_LOCATION_ACCESS);
                            }
                        });
                dialog.show();
            } else {
                // No explanation needed, we can request the permission.
                requestPermissions(
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        REQUEST_LOCATION_ACCESS);
            }//if-else
            return false;
        }else
            return  true;
    }//checkBlePermission


    /**
     * check to have the permission and the service enabled needed for stat a bluetooth scanning
     * @return true if we have all the requirements, false if we ask for something
     */
    public boolean checkAdapterAndPermission(){
        if(enableBluetoothAdapter()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if(enableLocationService())
                    return checkBlePermission();
            }else
                return true;
        }//if
        return false;
    }//checkAdapterAndPermission

    /**
     * to be called to check if the user has switched on the ble adapter
     * @param requestCode
     * @param resultCode
     * @param data
     * @return null if the request code is not a bleEnable, true/false if the the user enable the ble
     */
    public @Nullable Boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BT) {
            return resultCode == Activity.RESULT_OK;
        }//if request
        return null;
    }


    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults, BlePermissionAcquiredCallback callback) {
        if (grantResults.length == 0 )
            return;

        if(requestCode == REQUEST_LOCATION_ACCESS){
            // If request is cancelled, the result arrays are empty.
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //we have the permission try to start the scan again
                callback.onBlePermissionAcquired();
            } else {
                callback.onBlePermissionDenied();
            }//if-else
        }// if REQUEST_LOCATION_ACCESS
    }//onRequestPermissionsResult
}