package com.cpm.lorealbaautomation.geotag;

import static com.cpm.lorealbaautomation.constant.CommonFunctions.checkNetIsAvailable;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

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.Priority;
import com.google.android.gms.location.SettingsClient;
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.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.gson.JsonSyntaxException;
import com.cpm.lorealbaautomation.Database.Lorealba_Database;
import com.cpm.lorealbaautomation.R;
import com.cpm.lorealbaautomation.constant.AlertandMessages;
import com.cpm.lorealbaautomation.constant.CommonFunctions;
import com.cpm.lorealbaautomation.constant.CommonString;
import com.cpm.lorealbaautomation.delegates.PrefHelper;
import com.cpm.lorealbaautomation.gettersetter.GeotaggingBeans;
import com.cpm.lorealbaautomation.gsonGetterSetter.JourneyPlan;

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

import java.io.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class GeoTaggingActivity extends AppCompatActivity implements OnMapReadyCallback {
    double latitude = 0.0;
    double longitude = 0.0;
    FloatingActionButton fab, camera_fab;
    SharedPreferences preferences;
    private static final int REQUEST_LOCATION = 1;
    String username, str, counter_id, userType, visit_date, _path, _pathforcheck, img_str = "", app_ver = "0";
    Lorealba_Database db;
    ArrayList<GeotaggingBeans> geotaglist = new ArrayList<>();
    Context context;
    private GoogleMap mMap;
    JourneyPlan jcpGetset;
    private FusedLocationProviderClient fusedLocationClient;
    private LocationCallback locationCallback;
    private Marker currLocationMarker;
    private Geocoder geocoder;
    private double previousLatitude = 0.0, previousLongitude = 0.0;
    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
    private boolean cameraMovedOnce = false;
    UploadImageWithRetrofit upload;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_geo_tagging);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        upload = new UploadImageWithRetrofit(this);
        if (!CommonFunctions.isTablet(this)) {
            toolbar.setTitleTextAppearance(this, R.style.changestext_sizefor_mobile);
        }
        setTitle("GeoTag");
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        geocoder = new Geocoder(this);
        declaration();
        fab.setOnClickListener(view -> {
            try {
                startLocationUpdates();
                if (!img_str.isEmpty()) {
                    if (db.InsertSTOREgeotag(jcpGetset.getStoreId().toString(), counter_id, jcpGetset.getBID().toString(), username, latitude, longitude, img_str) > 0) {
                        img_str = "";
                        db.updateStatus(jcpGetset.getStoreId().toString(), jcpGetset.getCounterId().toString(),
                                jcpGetset.getBID().toString(), CommonString.KEY_Y, latitude, longitude);
                        new GeoTagUpload().execute();
                    } else {
                        AlertandMessages.showToastMsg(context, "Error in saving Geotag");
                    }
                } else {
                    AlertandMessages.showToastMsg(view.getContext(), getResources().getString(R.string.takeimage));
                }
            } catch (Exception e) {
                e.fillInStackTrace();
            }
        });
        camera_fab.setOnClickListener(view -> {
            try {
                if (checkNetIsAvailable(view.getContext())) {
                    if (latitude != 0.0 && longitude != 0.0) {
                        _pathforcheck = jcpGetset.getStoreId().toString() + "-" + jcpGetset.getCounterId().toString() +
                                "-" + jcpGetset.getBID().toString() + "_GeoTag-" + jcpGetset.getVisitDate().replace("/", "")
                                + "_" + getCurrentTime().replace(":", "") + ".jpg";
                        _path = CommonString.getImagesFolder(context) + _pathforcheck;
                        CommonFunctions.startAnncaCameraActivity(context, _path, null, false, CommonString.CAMERA_FACE_REAR);
                    } else {
                        AlertandMessages.showToastMsg(context, "Please wait for location");
                    }
                } else {
                    AlertandMessages.showToastMsg(context, getResources().getString(R.string.nonetwork));
                }
            } catch (Exception e) {
                e.fillInStackTrace();
            }
        });

        if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION);
        }
        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                for (Location location : locationResult.getLocations()) {
                    if (location != null) {
                        Log.e("jeevanp", location.toString());
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
                        // Handle the location update (e.g., update map, store location, etc.)
                        // Avoid 0.0 updates
                        if (latitude != 0.0 && longitude != 0.0) {
                            float[] results = new float[1];
                            Location.distanceBetween(previousLatitude, previousLongitude, latitude, longitude, results);
                            float distance = results[0];
                            // Update only if moved more than 10 meters
                            if (distance > 10) {
                                previousLatitude = latitude;
                                previousLongitude = longitude;

                                updateMapWithLocation(latitude, longitude);
                            }
                        }
                    }
                }
            }
        };
    }

    private void startLocationUpdates() {
        @SuppressLint("VisibleForTests") LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5000)
                .setMinUpdateIntervalMillis(1000)
                .build();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1001);
        }
    }

    private void updateMapWithLocation(double lat, double lon) {
        if (geocoder != null && mMap != null) {
            Log.e("jeevanp", "" + lat);
            String address = "";
            try {

                List<Address> addressList = geocoder.getFromLocation(lat, lon, 1);
                if (addressList != null && !addressList.isEmpty()) {
                    address = addressList.get(0).getAddressLine(0);
                }
            } catch (IOException e) {
                Log.e("MapError", "Geocoder error", e);
            }
            LatLng latLng = new LatLng(lat, lon);
            // Remove old marker
            if (currLocationMarker != null) {
                currLocationMarker.remove();
            }
            // Add new marker
            MarkerOptions markerOptions = new MarkerOptions()
                    .position(latLng)
                    .title(address)
                    .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));

            currLocationMarker = mMap.addMarker(markerOptions);

            // Move camera only once
            if (!cameraMovedOnce) {
                mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
                cameraMovedOnce = true;
            } else {
                mMap.animateCamera(CameraUpdateFactory.newLatLng(latLng));
            }
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }

    @Override
    public void onMapReady(@NonNull GoogleMap googleMap) {
        mMap = googleMap;
        mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        mMap.getUiSettings().setZoomControlsEnabled(true);
        mMap.getUiSettings().setCompassEnabled(true);
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(22.5726, 88.3639), 15));
        // Enable My Location layer
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            mMap.setMyLocationEnabled(true); // ✅ this shows blue dot
            mMap.getUiSettings().setMyLocationButtonEnabled(true); // ✅ this shows the GPS icon
            startLocationUpdates();
        } else {
            // request permission
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    LOCATION_PERMISSION_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    mMap.setMyLocationEnabled(true);
                    mMap.getUiSettings().setMyLocationButtonEnabled(true);
                }
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        checkgpsEnableDevice();
    }

    @Override
    protected void onStart() {
        super.onStart();
        startLocationUpdates();

    }

    public String getCurrentTime() {
        Calendar m_cal = Calendar.getInstance();
        @SuppressLint("SimpleDateFormat") SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
        return formatter.format(m_cal.getTime());
    }


    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (resultCode) {
            case 0:
                Log.i("MakeMachine", "User cancelled");
                break;
            case -1:
                if (_pathforcheck != null && !_pathforcheck.isEmpty()) {
                    try {
                        if (new File(CommonString.getImagesFolder(this) + _pathforcheck).exists()) {
                            camera_fab.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.mipmap.camera_tick));
                            camera_fab.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#888888")));
                            img_str = _pathforcheck;
                            _pathforcheck = "";
                        }
                    } catch (Exception e) {
                        e.fillInStackTrace();
                    }
                }

                break;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

    @SuppressLint("CutPasteId")
    void declaration() {
        context = this;
        preferences = PrefHelper.getPrefs(context);
        counter_id = preferences.getString(CommonString.KEY_COUNTER_ID, "");
        visit_date = preferences.getString(CommonString.KEY_DATE, "");
        username = preferences.getString(CommonString.KEY_USERNAME, "");
        userType = preferences.getString(CommonString.KEY_USER_TYPE, "");
        camera_fab = (FloatingActionButton) findViewById(R.id.camrabtn);
        fab = (FloatingActionButton) findViewById(R.id.fab);
        db = new Lorealba_Database(context);
        db.open();
        str = CommonString.getImagesFolder(this);
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        if (mapFragment != null) {
            mapFragment.getMapAsync(this);
        }
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        try {
            app_ver = String.valueOf(getPackageManager().getPackageInfo(getPackageName(), 0).versionName);
        } catch (PackageManager.NameNotFoundException ignored) {
        }
        db.open();
        if (!db.getStoreData(visit_date, username, counter_id).isEmpty()) {
            jcpGetset = db.getStoreData(visit_date, username, counter_id).get(0);
            fab.setVisibility(!jcpGetset.getGeoTag().equals("N") ? View.GONE : View.VISIBLE);
            camera_fab.setVisibility(!jcpGetset.getGeoTag().equals("N") ? View.GONE : View.VISIBLE);
        }
    }

    @SuppressLint("StaticFieldLeak")
    private class GeoTagUpload extends AsyncTask<Void, Void, String> {
        boolean uploadflag;
        String errormsg = "";
        Dialog dialog;
        ProgressBar pb;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            dialog = new Dialog(context);
            dialog.setContentView(R.layout.custom);
            dialog.setTitle(getResources().getString(R.string.dialog_title));
            dialog.setCancelable(false);
            dialog.show();
            pb = (ProgressBar) dialog.findViewById(R.id.progressBar1);
        }

        @Override
        protected String doInBackground(Void... params) {
            try {
                // uploading Geotag
                uploadflag = false;
                geotaglist = db.getinsertGeotaggingData(jcpGetset.getStoreId().toString(), counter_id, username, CommonString.KEY_N);
                if (!geotaglist.isEmpty()) {
                    String jsonString2 = getString();
                    Log.e("jsonString2", jsonString2);
                    String result = upload.downloadDataUniversal(jsonString2);
                    Log.e("jsonString2", result);
                    if (result.equalsIgnoreCase(CommonString.MESSAGE_NO_RESPONSE_SERVER)) {
                        uploadflag = false;
                        throw new SocketTimeoutException();
                    } else if (result.equalsIgnoreCase(CommonString.MESSAGE_SOCKETEXCEPTION)) {
                        uploadflag = false;
                        throw new IOException();
                    } else if (result.equalsIgnoreCase(CommonString.KEY_FAILURE)) {
                        uploadflag = false;
                        throw new Exception();
                    } else {
                        uploadflag = true;
                    }
                }
            } catch (IOException ex) {
                uploadflag = false;
                ex.fillInStackTrace();
                errormsg = CommonString.MESSAGE_INTERNET_NOT_AVALABLE;
            } catch (JsonSyntaxException ex) {
                uploadflag = false;
                ex.fillInStackTrace();
                errormsg = CommonString.MESSAGE_INVALID_JSON;
            } catch (Exception ex) {
                uploadflag = false;
                errormsg = CommonString.MESSAGE_EXCEPTION;
            }

            if (uploadflag) {
                return CommonString.KEY_SUCCESS;
            } else {
                return errormsg;
            }

        }

        private @NonNull String getString() throws JSONException {
            JSONArray topUpArray = new JSONArray();
            for (int j = 0; j < geotaglist.size(); j++) {
                JSONObject obj = getJsonObject(j);
                topUpArray.put(obj);
            }

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("MID", jcpGetset.getMID() != null ? jcpGetset.getMID() : 0);
            jsonObject.put("Keys", "GeoTag");
            jsonObject.put("JsonData", topUpArray.toString());
            jsonObject.put("UserId", username);
            return jsonObject.toString();
        }

        @NonNull
        private JSONObject getJsonObject(int j) throws JSONException {
            JSONObject obj = new JSONObject();
            obj.put("UserId",username);
            obj.put("StoreId", geotaglist.get(j).getStoreid());
            obj.put("CounterId", geotaglist.get(j).getCounterId());
            obj.put("bID", geotaglist.get(j).getBid());
            obj.put("VisitDate", jcpGetset.getVisitDate());
            obj.put("Latitude", geotaglist.get(j).getLatitude());
            obj.put("Longitude", geotaglist.get(j).getLongitude());
            obj.put("GeoImg", geotaglist.get(j).getImage());
            return obj;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            dialog.dismiss();
            if (result != null && result.equalsIgnoreCase(CommonString.KEY_SUCCESS)) {
                db.open();
                if (db.updateInsertedGeoTagStatus(jcpGetset.getStoreId().toString(), counter_id, username, CommonString.KEY_Y) > 0) {
                    img_str = "";
                    AlertandMessages.showToastMsg(context, "Geotag Saved Successfully");
                    finish();
                } else {
                    AlertandMessages.showAlert((Activity) context, "Error in updating Geotag status", true);
                }
            } else {
                AlertandMessages.showToastMsg((Activity) context, getResources().getString(R.string.failure) + " : " + errormsg);
                GeoTaggingActivity.this.finish();
            }
        }
    }

    private void checkgpsEnableDevice() {
        if (!hasGPSDevice(this)) {
            Toast.makeText(this, "Gps not Supported", Toast.LENGTH_SHORT).show();
        }
        final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(this)) {
            enableLocationSettings();
        } else {
            if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                hasGPSDevice(this);
            }
        }
    }

    private void enableLocationSettings() {
        LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, // priority
                5000                             // intervalMillis: 5 seconds
        ).setMinUpdateIntervalMillis(3000)       // fastest interval
                .build();
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true); // show dialog if GPS is off

        SettingsClient settingsClient = LocationServices.getSettingsClient(this);
        settingsClient.checkLocationSettings(builder.build()).addOnSuccessListener(locationSettingsResponse -> {
            // All location settings are satisfied. You can request location updates here.
        }).addOnFailureListener(e -> {
            if (e instanceof ResolvableApiException) {
                try {
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult((Activity) this, REQUEST_LOCATION);
                } catch (IntentSender.SendIntentException sendEx) {
                    // Ignore the error.
                    sendEx.fillInStackTrace();
                }
            }
        });
    }

    private boolean hasGPSDevice(Context context) {
        final LocationManager mgr = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        if (mgr == null) return false;
        final List<String> providers = mgr.getAllProviders();
        if (providers == null) return false;
        return providers.contains(LocationManager.GPS_PROVIDER);
    }

}
