package com.fusi24.entryPermitScanner.ui;

import android.Manifest;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;

import com.fusi24.entryPermitScanner.R;
import com.fusi24.entryPermitScanner.config.Constant;
import com.fusi24.entryPermitScanner.databinding.ActivityScanBinding;
import com.fusi24.entryPermitScanner.ui.scanresult.ScanResultActivity;
import com.fusi24.entryPermitScanner.util.LFScanProcessing;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

import im.delight.android.location.SimpleLocation;
import timber.log.Timber;

public class ScanActivity extends LFScanProcessing implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        LocationListener {

    public static final String ID_PERMIT = "id_permit";
    public static final String ID_DEVICE = "id_device";
    public static final String ID_CHECK_TYPE = "id_check_type";
    public static final String CHECK_TYPE_NAME = "check_type_name";

    private String idPermit, idDevice, idCheckType, checkTypeName, longLat;
    private ActivityScanBinding binding;
    private FusedLocationProviderClient locationClient;

    //Define a request code to send to Google Play services
    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private double currentLatitude;
    private double currentLongitude;

    //Define a simple location android
    private SimpleLocation simpleLocation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityScanBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);

        Toolbar toolbar = findViewById(R.id.toolbar);
        TextView toolbarTitle = findViewById(R.id.toolbar_text);

        if (toolbarTitle != null && toolbar != null) {
            toolbarTitle.setText(getString(R.string.app_name));
            setSupportActionBar(toolbar);
        }

        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayShowTitleEnabled(false);
        }

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                // The next two lines tell the new client that “this” current class will handle connection stuff
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                //fourth line adds the LocationServices API endpoint from GooglePlayServices
                .addApi(LocationServices.API)
                .build();

        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(10 * 1000)        // 10 seconds, in milliseconds
                .setFastestInterval(1000); // 1 second, in milliseconds

        // First Time init
        simpleLocation = new SimpleLocation(this);
        // if we can't access the location yet
        if (!simpleLocation.hasLocationEnabled()) {
            // ask the user to enable location access
            SimpleLocation.openSettings(this);
        }

        initView();
        initSound();
    }

    private void initView() {
        if (getIntent().getExtras() != null) {
            idPermit = getIntent().getExtras().getString(ID_PERMIT);
            idDevice = getIntent().getExtras().getString(ID_DEVICE);
            idCheckType = String.valueOf(getIntent().getExtras().getInt(ID_CHECK_TYPE));
            checkTypeName = getIntent().getExtras().getString(CHECK_TYPE_NAME);
        }

        setStatusScan();
        locationClient = LocationServices.getFusedLocationProviderClient(this);
        getLocation();
        getSimpleLocation();
        binding.toggleScan.setOnCheckedChangeListener((buttonView, isChecked) -> statusScanner());
    }

    @Override
    protected void onResume() {
        super.onResume();
        statusScanner();
        //Now lets connect to the API
        mGoogleApiClient.connect();

        // make the device update its location
        simpleLocation.beginUpdates();
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Stop scanner when scan activity pause
        onStop();
        //Disconnect from API onPause()
        if (mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
        }

        // stop location updates (saves battery)
        simpleLocation.endUpdates();
    }

    private void setStatusScan() {
        switch (checkTypeName) {
            case "Check In":
                binding.tvStatusScan.setBackground(getDrawable(R.drawable.bg_green));
                break;
            case "Check Out":
            default:
                binding.tvStatusScan.setBackground(getDrawable(R.drawable.bg_blue));
                break;
        }
        binding.tvStatusScan.setText(checkTypeName);
    }

    private void statusScanner() {
        if (binding.toggleScan.isChecked()) {
            onStart();
        } else
            onStop();
    }

    void startInstance(String rfidCardNumber) {
        Intent intent = new Intent(this, ScanResultActivity.class);
        intent.putExtra(ScanResultActivity.RFID_CARD_NUMBER, rfidCardNumber);
        intent.putExtra(ScanResultActivity.ID_PERMIT, idPermit);
        intent.putExtra(ScanResultActivity.ID_DEVICE, idDevice);
        intent.putExtra(ScanResultActivity.ID_CHECK_TYPE, idCheckType);
        intent.putExtra(ScanResultActivity.CHECK_TYPE_NAME, checkTypeName);
        intent.putExtra(ScanResultActivity.LOCATION, longLat);
        startActivityForResult(intent, 1);
    }

    // This method for read chip number in the card
    @Override
    protected void onDataReceived(byte[] buffer, int size) {
        runOnUiThread(() -> {
            if (rfidCardNumber != null) {
                if (size > 0) {
                    if (size >= 5) {
                        byte[] tempBuf = new byte[size - 4];
                        System.arraycopy(buffer, 4, tempBuf, 0, size - 4);//discard 4 bit
                        String temStr = new String(tempBuf);
                        int temInt = Integer.parseInt(temStr, 16);
                        soundpool.play(soundid, 1, 1, 0, 0, 1);
                        rfidCardNumber = Integer.toString(temInt);

                        Timber.i("Hasil dari RFID LF: %s", rfidCardNumber);
                        startInstance(rfidCardNumber);
                    } else {
                        // receipt data 4 digit to start
                        rfidCardNumber = new String(buffer, 0, size);
                    }
                }
            }
        });
    }

    private void getLocation() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, Constant.PERMISSIONS_RFID, 1000);
            return;
        }
        locationClient.getLastLocation().addOnSuccessListener(this, location -> {
            if (location != null) {
                double latitude = location.getLatitude();
                double longitude = location.getLongitude();
                longLat = longitude + "," + latitude;
                Timber.i("DEVELOPER Location 1 : " + location.getLatitude() + " , " + location.getLongitude());
            }
        });
        locationClient.getLastLocation().addOnCanceledListener(() -> Timber.i("Get last location cancelled"));
        locationClient.getLastLocation().addOnFailureListener(Timber::e);
    }

    private void getSimpleLocation(){
        double latitude = simpleLocation.getLatitude();
        double longitude = simpleLocation.getLongitude();
        longLat = longitude + "," + latitude;
        Timber.i("Simple Location ==> Latitude : " + latitude + ", Longitude : " + longitude);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        binding = null;
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, Constant.PERMISSIONS_RFID, 1000);
            return;
        }
        Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (location == null) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        } else {
            //If everything went fine lets get latitude and longitude
            currentLatitude = location.getLatitude();
            currentLongitude = location.getLongitude();
            longLat = currentLongitude + "," + currentLatitude;
            Timber.i("Latitude : " + currentLatitude + ", Longitude : " + currentLongitude);
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        /*
         * Google Play services can resolve some errors it detects.
         * If the error has a resolution, try sending an Intent to
         * start a Google Play services activity that can resolve
         * error.
         */
        if (connectionResult.hasResolution()) {
            try {
                // Start an Activity that tries to resolve the error
                connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
                /*
                 * Thrown if Google Play services canceled the original
                 * PendingIntent
                 */
            } catch (IntentSender.SendIntentException e) {
                // Log the error
                e.printStackTrace();
            }
        } else {
            /*
             * If no resolution is available, display a dialog to the
             * user with the error.
             */
            Timber.tag("Error").e("Location services connection failed with code %s", connectionResult.getErrorCode());
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        currentLatitude = location.getLatitude();
        currentLongitude = location.getLongitude();

        longLat = currentLongitude + "," + currentLatitude;
        Timber.i("Latitude : " + currentLatitude + ", Longitude : " + currentLongitude);
    }
}
