package com.aplusinformatique.aplusmanager.Activitys;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import androidx.fragment.app.FragmentActivity;
import androidx.room.Room;

import com.aplusinformatique.aplusmanager.BuildConfig;
import com.aplusinformatique.aplusmanager.Classes.Singleton;
import com.aplusinformatique.aplusmanager.R;
import com.aplusinformatique.aplusmanager.Services.DebutGeolocalisationV3;
import com.aplusinformatique.aplusmanager.db.AppDatabase;
import com.aplusinformatique.aplusmanager.db.Geofence;
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.CameraPosition;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
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 java.util.ArrayList;
import java.util.List;

import static com.aplusinformatique.aplusmanager.Classes.GeofenceBroadcastReceiver.ACTION_GEOFENCE_TRIGGER;
import static com.aplusinformatique.aplusmanager.Services.DebutGeolocalisationV3.ACTION_ALARM_POSITION_TRIGGERED;
import static com.aplusinformatique.aplusmanager.Services.DebutGeolocalisationV3.ACTION_ENVOI_POSITION;
import static com.aplusinformatique.aplusmanager.Services.DebutGeolocalisationV3.ACTION_HEART_BEAT;
import static com.aplusinformatique.aplusmanager.Services.DebutGeolocalisationV3.INTENT_PARAMETER_ALARM_GEOFENCE_ID;

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private static final String TAG = "MapsActivity";

    private BroadcastReceiver receiverHeartBeatBroadcastReceiver, receiverPositionBroadcastReceiver, receiverGeofenceBroadcastReceiver, receiverAlarmBroadcastReceiver;

    private GoogleMap mMap;
    private Marker currentPositionMarker, currentSelectedPositionMarker;

    private boolean moveFirstTime = true;

    private EditText etId, etRadius, etWarningDelay, etCheckDelay;
    private List<Geofence> currentGeofenceList;
    private List<Marker> currentMarkerList;
    private List<Circle> currentCircleList;

    // Developper mode
    private View developperGroup;
    private Button developperToggle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        currentGeofenceList = new ArrayList<>();
        currentMarkerList = new ArrayList<>();
        currentCircleList = new ArrayList<>();

        etId = findViewById(R.id.activity_maps_edittext_id);
        etRadius = findViewById(R.id.activity_maps_edittext_radius);
        etWarningDelay = findViewById(R.id.activity_maps_edittext_warning_delay);
        etCheckDelay = findViewById(R.id.activity_maps_edittext_check_delay);

        findViewById(R.id.activity_maps_button_send).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CameraPosition currentCameraPosition = mMap.getCameraPosition();

                // Add the current position to the geofence list, and send it to the service.
                Geofence currentGeofence = new Geofence(
                        etId.getText().toString(),
                        currentCameraPosition.target.latitude,
                        currentCameraPosition.target.longitude,
                        Float.parseFloat(etRadius.getText().toString()),
                        Long.parseLong(etWarningDelay.getText().toString()),
                        Long.parseLong(etCheckDelay.getText().toString()),
                        "GOOGLEMAPS"
                );

                LatLng current = new LatLng(currentCameraPosition.target.latitude, currentCameraPosition.target.longitude);
                currentMarkerList.add(mMap.addMarker(new MarkerOptions().position(current).title(etId.getText().toString())));

                currentCircleList.add(mMap.addCircle(new CircleOptions()
                        .center(current)
                        .radius(currentGeofence.radius)
                        .strokeWidth(0f)
                        .fillColor(0x550000FF)));

                currentGeofenceList.add(currentGeofence);
                DebutGeolocalisationV3.sendGeoFenceBroadCast(
                        MapsActivity.this,
                        currentGeofenceList
                );

            }
        });

        findViewById(R.id.activity_maps_button_clear).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clearDisplay();
            }
        });


        findViewById(R.id.activity_maps_button_clear_db).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new ClearDatabaseTask().execute();
                clearDisplay();
            }
        });


        findViewById(R.id.activity_maps_button_load).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new LoadGeofenceFromDBTask().execute();
            }
        });

        if (BuildConfig.DEBUG) {
            Log.d(TAG, "DEVICE ID = " + Settings.Secure.getString(MapsActivity.this.getContentResolver(), Settings.Secure.ANDROID_ID));
        }

        if (Settings.Secure.getString(MapsActivity.this.getContentResolver(), Settings.Secure.ANDROID_ID).equals("dfb76109e8dbbaef") ||
                Settings.Secure.getString(MapsActivity.this.getContentResolver(), Settings.Secure.ANDROID_ID).equals("6d47f639e0f54561") ||
                Settings.Secure.getString(MapsActivity.this.getContentResolver(), Settings.Secure.ANDROID_ID).equals("e505bbfe14962c7c") ||
                Settings.Secure.getString(MapsActivity.this.getContentResolver(), Settings.Secure.ANDROID_ID).equals("b02f975f1a4bcc87")
        ) {
            developperGroup = findViewById(R.id.developper);
            developperToggle = findViewById(R.id.activity_maps_button_toggle);

            developperToggle.setVisibility(View.VISIBLE);
            developperToggle.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    developperGroup.setVisibility((developperGroup.getVisibility() == View.VISIBLE) ? View.GONE : View.VISIBLE);
                }
            });
        }

        new LoadGeofenceFromDBTask().execute();
    }

    private void clearDisplay() {
        currentGeofenceList.clear();

        for (Marker currentMarker : currentMarkerList) {
            currentMarker.remove();
        }
        currentMarkerList.clear();

        for (Circle currentCircle : currentCircleList) {
            currentCircle.remove();
        }
        currentCircleList.clear();
    }


    /**
     * Manipulates the map once available.
     * This callback is triggered when the map is ready to be used.
     * This is where we can add markers or lines, add listeners or move the camera. In this case,
     * we just add a marker near Sydney, Australia.
     * If Google Play services is not installed on the device, the user will be prompted to install
     * it inside the SupportMapFragment. This method will only be triggered once the user has
     * installed Google Play services and returned to the app.
     */
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Add a marker in Marseille and move the camera
        LatLng marseille = new LatLng(43, 5);
        currentPositionMarker = mMap.addMarker(new MarkerOptions().position(marseille).title("Marker of current location").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)));
        //currentSelectedPositionMarker = mMap.addMarker(new MarkerOptions().position(marseille).title("Marker of current selected").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(marseille));

        mMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
            @Override
            public void onCameraMove() {
                //currentSelectedPositionMarker.setPosition(mMap.getCameraPosition().target);
            }
        });
    }

    private void registerReceivers() {

        if (BuildConfig.DEBUG) {
            Log.d(TAG, "registerReceivers ");
        }

        // register HeartBeat
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_HEART_BEAT);
        receiverHeartBeatBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                DebutGeolocalisationV3.sendBroadcastHeartBeat(MapsActivity.this);
            }
        };
        registerReceiver(receiverHeartBeatBroadcastReceiver, filter);


        // Register positions
        IntentFilter filterPosition = new IntentFilter();
        filterPosition.addAction(ACTION_ENVOI_POSITION);
        receiverPositionBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
//                if (BuildConfig.DEBUG) {
//                    Log.d(TAG, "onReceive ACTION_ENVOI_POSITION latitude " + intent.getStringExtra("latitude"));
//                    Log.d(TAG, "onReceive ACTION_ENVOI_POSITION longitude " + intent.getStringExtra("longitude"));
//                    Log.d(TAG, "onReceive ACTION_ENVOI_POSITION speed " + intent.getStringExtra("speed"));
//                    Log.d(TAG, "onReceive ACTION_ENVOI_POSITION accuracy " + intent.getStringExtra("accuracy"));
//                    Log.d(TAG, "onReceive ACTION_ENVOI_POSITION date " + intent.getStringExtra("date"));
//                }

                LatLng currentPosition = new LatLng(Double.parseDouble(intent.getStringExtra("latitude")), Double.parseDouble(intent.getStringExtra("longitude")));

                currentPositionMarker.setPosition(currentPosition);

                if (moveFirstTime) {
                    moveFirstTime = false;
                    mMap.moveCamera(CameraUpdateFactory.zoomTo(16));
                    mMap.moveCamera(CameraUpdateFactory.newLatLng(currentPosition));
                }

            }
        };
        registerReceiver(receiverPositionBroadcastReceiver, filterPosition);

        // Register geofence
        IntentFilter filterGeofence = new IntentFilter();
        filterGeofence.addAction(ACTION_GEOFENCE_TRIGGER);
        receiverGeofenceBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (BuildConfig.DEBUG) {
                    Log.d(TAG, "onReceive ACTION_GEOFENCE_TRIGGER geofenceId " + intent.getStringExtra("geofenceId"));
                }
            }
        };
        registerReceiver(receiverGeofenceBroadcastReceiver, filterGeofence);


        // Register Alarme
        IntentFilter filterAlarm = new IntentFilter();
        filterAlarm.addAction(ACTION_ALARM_POSITION_TRIGGERED);
        receiverAlarmBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (BuildConfig.DEBUG) {
                    Log.d(TAG, "onReceive ACTION_ALARM_POSITION_TRIGGERED geofenceId " + intent.getStringExtra(INTENT_PARAMETER_ALARM_GEOFENCE_ID));
                }
            }
        };
        registerReceiver(receiverAlarmBroadcastReceiver, filterAlarm);
    }

    private void unregisterReceivers() {
        if (BuildConfig.DEBUG) {
            Log.d(TAG, "unregisterReceivers ");
        }

        if (receiverHeartBeatBroadcastReceiver != null) {
            unregisterReceiver(receiverHeartBeatBroadcastReceiver);
        }

        if (receiverPositionBroadcastReceiver != null) {
            unregisterReceiver(receiverPositionBroadcastReceiver);
        }

        if (receiverGeofenceBroadcastReceiver != null) {
            unregisterReceiver(receiverGeofenceBroadcastReceiver);
        }
        if (receiverAlarmBroadcastReceiver != null) {
            unregisterReceiver(receiverAlarmBroadcastReceiver);
        }
    }

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

        if (BuildConfig.DEBUG) {
            Log.d(TAG, "onResume ");
        }

        registerReceivers();
    }

    @Override
    protected void onPause() {
        if (BuildConfig.DEBUG) {
            Log.d(TAG, "onPause ");
        }

        unregisterReceivers();
        super.onPause();
    }

    // AsyncTask<Params, Progress, Result>
    private class LoadGeofenceFromDBTask extends AsyncTask<Void, Void, Integer> {

        protected Integer doInBackground(Void... params) {

            // Clear all the markers
            currentGeofenceList.clear();

            for (Marker currentMarker : currentMarkerList) {
                currentMarker.remove();
            }
            currentMarkerList.clear();

            for (Circle currentCircle : currentCircleList) {
                currentCircle.remove();
            }
            currentCircleList.clear();

            // Load them from the database
            AppDatabase db = Singleton.getInstance().getDb(getApplicationContext());
            List<Geofence> geofenceList = db.geofenceDao().getAll();

            int counter = 0;
            for (Geofence currentGeofenceDatabase : geofenceList) {
                // Add the current position to the geofence list, and send it to the service.
                Geofence currentGeofence = new Geofence(
                        currentGeofenceDatabase.uid,
                        currentGeofenceDatabase.latitude,
                        currentGeofenceDatabase.longitude,
                        currentGeofenceDatabase.radius,
                        currentGeofenceDatabase.warningDelay,
                        currentGeofenceDatabase.checkDelay,
                        currentGeofenceDatabase.routingApi
                );
                currentGeofenceList.add(currentGeofence);

                counter++;
            }

            return counter;
        }

        protected void onPostExecute(Integer result) {
            if (BuildConfig.DEBUG) {
                Log.d(TAG, "onPostExecute result =" + result);
            }
            for (Geofence currentGeofenceDatabase : currentGeofenceList) {
                LatLng current = new LatLng(currentGeofenceDatabase.latitude, currentGeofenceDatabase.longitude);
                currentMarkerList.add(mMap.addMarker(new MarkerOptions().position(current).title(currentGeofenceDatabase.uid)));

                currentCircleList.add(mMap.addCircle(new CircleOptions()
                        .center(current)
                        .radius(currentGeofenceDatabase.radius)
                        .strokeWidth(0f)
                        .fillColor(0x550000FF)));
            }
        }
    }

    // AsyncTask<Params, Progress, Result>
    private class ClearDatabaseTask extends AsyncTask<Void, Void, Void> {

        protected void onPreExecute() {
            // TODO : Launched UI thread before the task is executed => Display a progress bar
        }

        protected Void doInBackground(Void... params) {

            // Load them from the database
            AppDatabase db = Singleton.getInstance().getDb(getApplicationContext());
            db.geofenceDao().deleteAll();

            if (BuildConfig.DEBUG) {
                Log.d(TAG, "ClearDatabaseTask doInBackground database is now clear");
            }

            return null;
        }

        protected void onProgressUpdate(Void... progress) {
            // invoked on the UI thread after a call to publishProgress(Progress...)
            // TODO : Do something with the Void progress[0]
        }

        protected void onPostExecute(Void result) {
            // TODO invoked on the UI thread after the background computation finishes
        }
    }
}
