package com.anand.geofence;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.anand.firebaseapp.R;
import com.anand.firebaseapp.databinding.ActivityMapsBinding;
import com.anand.geofence.reference.AppSharedpreferences;
import com.anand.geofence.retrofit.ApiClient;
import com.anand.geofence.sample.GeofenceBroadcastReceiver;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.gson.Gson;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

    private GoogleMap map;
    private ActivityMapsBinding binding;
    private ArrayList<Geofence> geofenceList = new ArrayList<>();
    private GeofencingClient geoClient;
    private static final String TAG = "MapsActivity";
    private static final int REQUEST_TURN_DEVICE_LOCATION_ON = 20;
    private static final int REQUEST_FOREGROUND_AND_BACKGROUND_PERMISSION_RESULT_CODE = 3;
    private static final int REQUEST_FOREGROUND_ONLY_PERMISSIONS_REQUEST_CODE = 4;
    private static final int REQUEST_LOCATION_PERMISSION = 10;
    private boolean gadgetQ = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;
    private PendingIntent geofenceIntent;
    boolean resolve = true;
    private ApiClient apiClient;
    private AppSharedpreferences appSharedpreferences;
    List<com.anand.geofence.model.response.geofence.Geofence> locationList;
    List<String> latLong, radius;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMapsBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        apiClient = apiClient.getInstance();
        appSharedpreferences = AppSharedpreferences.getInstance(MapsActivity.this);

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        if (mapFragment != null) {
            mapFragment.getMapAsync(this);
        }

        createChannel();
        getLocations();

        geoClient = LocationServices.getGeofencingClient(this);
        geofenceIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, GeofenceBroadcastReceiver.class), PendingIntent.FLAG_MUTABLE);

        double latitude = 11.0030654;
        double longitude = 76.974619;
        float radius = 200f;

      /*  geofenceList.add(new Geofence.Builder()
                .setRequestId("GeofenceId")
                .setCircularRegion(latitude, longitude, radius)
                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
                .build());*/



        if (locationList != null) {
            for (int i = 0; i < locationList.size(); i++) {
                Log.i("getGeoid","getGeoid : "+locationList.get(i).getGeoid());
                geofenceList.add(new Geofence.Builder()
                        .setRequestId(locationList.get(i).getLat() + "," + locationList.get(i).getLog()+","+locationList.get(i).getGeoid()+","+locationList.get(i).getIdentifier())
                        .setCircularRegion(Double.parseDouble(locationList.get(i).getLat()), Double.parseDouble(locationList.get(i).getLog()), Float.valueOf(locationList.get(i).getRadius()))
                        .setExpirationDuration(Geofence.NEVER_EXPIRE)
                        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
                        .build());
            }
        }

        Log.i("GeofenceList", "size : " + geofenceList.size() + "   " + String.valueOf(geofenceList));

    }

    private void getLocations() {
        String geoLocationJson = appSharedpreferences.getString("geoLocation");
        locationList = new ArrayList<>();
        try {
            JSONArray jsonArray = new JSONArray(geoLocationJson);
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                com.anand.geofence.model.response.geofence.Geofence geofence = new com.anand.geofence.model.response.geofence.Geofence();
                geofence.setIdentifier(jsonObject.getString("identifier"));
                geofence.setLat(jsonObject.getString("lat"));
                geofence.setLog(jsonObject.getString("log"));
                geofence.setGeoid(jsonObject.getString("geoid"));
                geofence.setRadius(jsonObject.getString("radius"));
                locationList.add(geofence);

            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        Log.i("LocationList", "LocationList : " + locationList);
        List<String> latitudes = new ArrayList<>();
        List<String> longitudes = new ArrayList<>();
        radius = new ArrayList<>();
        latLong = new ArrayList<>();
        for (com.anand.geofence.model.response.geofence.Geofence geofence : locationList) {
            latitudes.add(geofence.getLat());
            longitudes.add(geofence.getLog());
            radius.add(geofence.getRadius());

            latLong.add(geofence.getLat() + "," + geofence.getLog() + "," + geofence.getRadius());
        }
        Log.i("Latitudes Count", String.valueOf(latitudes.size()));
        Log.i("LatLong Count", String.valueOf(latLong.size()));
        Gson gson2 = new Gson();
        String json2 = gson2.toJson(latLong);
        Log.i("LatLong", json2);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;

        if (latLong != null) {
            for (int i = 0; i < latLong.size(); i++) {
                String Lat = latLong.get(i).split(",")[0];
                String Long = latLong.get(i).split(",")[1];
                LatLng latLng = new LatLng(Double.valueOf(Lat), Double.valueOf(Long));
                CircleOptions circleOptions = new CircleOptions()
                        .center(latLng)
                        .radius(Double.parseDouble(radius.get(i))) // in meters
                        .fillColor(0x40ff0000) // transparent red fill
                        .strokeColor(Color.RED) // border color
                        .strokeWidth(5f); // border width

                map.addCircle(circleOptions);
                float zoomLevel = 14f;
                map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoomLevel));
            }
        }

        startLocation();
    }

    private boolean isPermissionGranted() {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
    }

    private void startLocation() {
        if (isPermissionGranted()) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            map.setMyLocationEnabled(true);
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
        }
    }

    private GeofencingRequest seekGeofencing() {
        return new GeofencingRequest.Builder()
                .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
                .addGeofences(geofenceList)
                .build();
    }

    private void addGeofence() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        geoClient.addGeofences(seekGeofencing(), geofenceIntent).addOnSuccessListener(aVoid -> {
            Log.i("location", "geofence added");
            Toast.makeText(this, "Geofences added", Toast.LENGTH_SHORT).show();
        }).addOnFailureListener(e -> {
            Log.i("location", "Failed to add geofences");
            Toast.makeText(this, "Failed to add geofences", Toast.LENGTH_SHORT).show();
        });
    }

    private void removeGeofence() {
        geoClient.removeGeofences(geofenceIntent).addOnSuccessListener(aVoid -> {
            Toast.makeText(this, "Geofences removed", Toast.LENGTH_SHORT).show();
        }).addOnFailureListener(e -> {
            Toast.makeText(this, "Failed to remove geofences", Toast.LENGTH_SHORT).show();
        });
    }

    private void examinePermissionAndInitiateGeofence() {
        if (authorizedLocation()) {
            validateGadgetAreaInitiateGeofence(true);
        } else {
            askLocationPermission();
        }
    }

    @TargetApi(29)
    private boolean authorizedLocation() {
        boolean formalizeForeground = (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
        boolean formalizeBackground;
        if (gadgetQ) {
            formalizeBackground = (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED);
        } else {
            formalizeBackground = true;
        }
        return formalizeForeground && formalizeBackground;
    }

    @TargetApi(29)
    private void askLocationPermission() {
        if (authorizedLocation()) {
            return;
        }
        String[] grantingPermission = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
        int customResult;
        if (gadgetQ) {
            grantingPermission = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION};
            customResult = REQUEST_FOREGROUND_AND_BACKGROUND_PERMISSION_RESULT_CODE;
        } else {
            customResult = REQUEST_FOREGROUND_ONLY_PERMISSIONS_REQUEST_CODE;
        }
        Log.d(TAG, "askLocationPermission: ");
        ActivityCompat.requestPermissions(this, grantingPermission, customResult);
    }

    private void validateGadgetAreaInitiateGeofence(boolean resolve) {
        LocationRequest locationRequest = LocationRequest.create().setPriority(LocationRequest.PRIORITY_LOW_POWER);
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
        LocationServices.getSettingsClient(this).checkLocationSettings(builder.build()).addOnFailureListener(exception -> {
            if (exception instanceof ResolvableApiException && this.resolve) {
                try {
                    ((ResolvableApiException) exception).startResolutionForResult(this, REQUEST_TURN_DEVICE_LOCATION_ON);
                } catch (IntentSender.SendIntentException sendEx) {
                    Log.d(TAG, "Error getting location settings resolution: " + sendEx.getMessage());
                }
            } else {
                Toast.makeText(this, "Enable your location", Toast.LENGTH_SHORT).show();
            }
        }).addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                addGeofence();
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_LOCATION_PERMISSION) {
            if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                startLocation();
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        validateGadgetAreaInitiateGeofence(false);
    }

    @Override
    protected void onStart() {
        super.onStart();
        examinePermissionAndInitiateGeofence();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        removeGeofence();
    }

    private void createChannel() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel notificationChannel = new NotificationChannel("GeofenceChannel", "Channel1", NotificationManager.IMPORTANCE_HIGH);
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(notificationChannel);
            }
        }
    }
}
