package br.com.minhavia.minhavia.service;

import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.ValueEventListener;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;

import br.com.minhavia.minhavia.dao.PavimentoIrregularDatabase;
import br.com.minhavia.minhavia.firebase.PavimentoIrregularFirebase;
import br.com.minhavia.minhavia.model.PavimentoIrregular;
import br.com.minhavia.minhavia.util.CalcularDistancia;
import br.com.minhavia.minhavia.util.Constantes;

public class GeoBackgroundService extends Service {

    private static final String TAG = "MV-GeoBackground";
    public static String str_receiver = "br.com.minhavia.minhavia.receive";
    private Context context;
    private Intent intent;
    private Handler mHandler = new Handler();
    private Timer mTimer = null;
    private PavimentoIrregularDatabase db;
    private DatabaseReference pavimentoIrregularFirebase;
    private List<PavimentoIrregular> listaIrregulares = null;
    private TimerTaskToGetLocation timerTaskToGetLocation = new TimerTaskToGetLocation();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(3, new Notification());

        db = PavimentoIrregularDatabase.getDATABASE(GeoBackgroundService.this);
        pavimentoIrregularFirebase = PavimentoIrregularFirebase.getFirebaseDatabase();
        mTimer = new Timer();
        mTimer.schedule(new TimerTaskToGetLocation(), 5, Constantes.TIMER_REPEAT_GEO);
        intent = new Intent(str_receiver);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand()");
        this.context = this;
        timerTaskToGetLocation.doStop();
        timerTaskToGetLocation.cancel();
        timerTaskToGetLocation.setExecutandoThread(false);
        timerTaskToGetLocation.run();
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy()");
        if (mTimer != null) {
            mTimer.cancel();
        }

        timerTaskToGetLocation.doStop();
        timerTaskToGetLocation.cancel();
        timerTaskToGetLocation.setExecutandoThread(false);
        encerrarServico();
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.e(TAG, "onTaskRemoved()");
        timerTaskToGetLocation.doStop();
        timerTaskToGetLocation.cancel();
        timerTaskToGetLocation.setExecutandoThread(false);
        encerrarServico();
        super.onTaskRemoved(rootIntent);
    }

    @Override
    public void onLowMemory() {
        Log.e(TAG, "onLowMemory()");

        timerTaskToGetLocation.doStop();
        timerTaskToGetLocation.cancel();
        timerTaskToGetLocation.setExecutandoThread(false);
        encerrarServico();
        super.onLowMemory();
    }

    private void encerrarServico() {
        if (mTimer != null) {
            mTimer.cancel();
        }
        stopSelf();
    }

    public void updateAddress(){
        List<PavimentoIrregular> lista = db.pavimentoIrregularDAO().getAllWithoutAddress();
        if(lista != null){
            for(PavimentoIrregular p : lista){
                long tmpInit = System.currentTimeMillis();
                getAddress(p);
                db.pavimentoIrregularDAO().update(p);
                Log.e(TAG, "TEMPO onLocationChanged: "+(System.currentTimeMillis() - tmpInit));
            }
        }
        encerrarServico();
    }

    public void getAddress(PavimentoIrregular pavimentoIrregular){
        Geocoder geocoder = new Geocoder(context, Locale.getDefault());
        try {
            List <Address> addressList = geocoder.getFromLocation(Double.parseDouble(pavimentoIrregular.getLatitude()), Double.parseDouble(pavimentoIrregular.getLongitude()), 1);
            if (addressList != null && addressList.size() > 0) {
                Address address = addressList.get(0);
                pavimentoIrregular.setPais(address.getCountryCode());
                pavimentoIrregular.setUf(address.getAdminArea());
                pavimentoIrregular.setCidade(address.getLocality() != null ? address.getLocality() : address.getSubAdminArea());
                pavimentoIrregular.setLogradouro(address.getThoroughfare());
            }
        } catch (IOException e) {
            Log.e("Location Address Loader", "Unable connect to Geocoder", e);
            encerrarServico();
        }

    }

    public void enviarPavimentoIrregular() {

        listaIrregulares = db.pavimentoIrregularDAO().getPavimentos(true);

            pavimentoIrregularFirebase.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    if (listaIrregulares != null) {
                        for (final PavimentoIrregular pavimentoIrregular : listaIrregulares) {
                            if(pavimentoIrregular.getIdFirebase() != null) {
                                Iterable<DataSnapshot> listaDataSnapshots = dataSnapshot.child(pavimentoIrregular.getIdFirebase()).getChildren();

                                PavimentoIrregular pSnapShot = null;
                                PavimentoIrregular pavimentoIrregularSelecionado = null;
                                for (DataSnapshot d : listaDataSnapshots) {
                                    pSnapShot = (PavimentoIrregular) d.getValue();
                                    if (pavimentoIrregularSelecionado == null && CalcularDistancia.ehMesmoPonto(pavimentoIrregular.getLatitude(), pavimentoIrregular.getLongitude(), pSnapShot.getLatitude(), pSnapShot.getLongitude())) {
                                        pavimentoIrregularSelecionado = pSnapShot.getClone();
                                    }
                                }

                                if (pavimentoIrregularSelecionado != null) {
                                    pavimentoIrregularSelecionado.setQuantidadeOcorrencias(pavimentoIrregularSelecionado.getQuantidadeOcorrencias() + 1);
                                    pavimentoIrregularFirebase.child(pavimentoIrregularSelecionado.getPais()).
                                            child(pavimentoIrregularSelecionado.getUf()).
                                            child(pavimentoIrregularSelecionado.getCidade()).
                                            child(pavimentoIrregularSelecionado.getBairro()).
                                            child(pavimentoIrregularSelecionado.getLogradouro()).
                                            child(pavimentoIrregularSelecionado.getIdFirebase()).
                                            setValue(pavimentoIrregularSelecionado);

                                } else {
                           /* pavimentoIrregular.setQuantidadeOcorrencias(1);
                            pavimentoIrregularFirebase.child(pavimentoIrregular.getPais()).
                                    child(pavimentoIrregular.getUf()).
                                    child(pavimentoIrregular.getCidade()).
                                    child(pavimentoIrregular.getBairro()).
                                    child(pavimentoIrregular.getLogradouro()).
                                    child(pavimentoIrregular.getIdFirebase()).
                                    setValue(pavimentoIrregular); */

                                }
                            }
                        }
                        listaIrregulares = null;
                    }
                }


                @Override
                public void onCancelled(DatabaseError databaseError) {
                }
            });

        db.pavimentoIrregularDAO().deletePavimentos(true);
    }


    public void removerPavimentoNaoIrregular() {

        List<PavimentoIrregular> listaIrregulares = db.pavimentoIrregularDAO().getPavimentos(false);


        for (final PavimentoIrregular pavimentoIrregular : listaIrregulares) {

            pavimentoIrregularFirebase.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    boolean filmeJaCadastrado = dataSnapshot.hasChild(pavimentoIrregular.getIdFirebase());

                    Iterable<DataSnapshot> listaDataSnapshots = dataSnapshot.child(pavimentoIrregular.getPais()).
                            child(pavimentoIrregular.getUf()).
                            child(pavimentoIrregular.getCidade()).
                            child(pavimentoIrregular.getBairro()).
                            child(pavimentoIrregular.getLogradouro()).getChildren();

                    PavimentoIrregular pSnapShot = null;
                    PavimentoIrregular pavimentoIrregularSelecionado = null;
                    for (DataSnapshot d : listaDataSnapshots) {
                        pSnapShot = (PavimentoIrregular) d.getValue();
                        if (pavimentoIrregularSelecionado == null && CalcularDistancia.ehMesmoPonto(pavimentoIrregular.getLatitude(), pavimentoIrregular.getLongitude(), pSnapShot.getLatitude(), pSnapShot.getLongitude())) {
                            pavimentoIrregularSelecionado = pSnapShot.getClone();
                        }
                    }

                    if (pavimentoIrregularSelecionado != null) {
                        pavimentoIrregularSelecionado.setQuantidadeOcorrencias(pavimentoIrregularSelecionado.getQuantidadeOcorrencias() + 1);
                        pavimentoIrregularFirebase.child(pavimentoIrregularSelecionado.getPais()).
                                child(pavimentoIrregularSelecionado.getUf()).
                                child(pavimentoIrregularSelecionado.getCidade()).
                                child(pavimentoIrregularSelecionado.getBairro()).
                                child(pavimentoIrregularSelecionado.getLogradouro()).
                                child(pavimentoIrregularSelecionado.getIdFirebase()).
                                setValue(pavimentoIrregularSelecionado);

                    } else {
                        /*pavimentoIrregularSelecionado.setQuantidadeOcorrencias(1);
                        pavimentoIrregularFirebase.child(pavimentoIrregular.getPais()).
                                child(pavimentoIrregular.getUf()).
                                child(pavimentoIrregular.getCidade()).
                                child(pavimentoIrregular.getBairro()).
                                child(pavimentoIrregular.getLogradouro()).
                                child(pavimentoIrregular.getIdFirebase()).
                                setValue(pavimentoIrregular);*/

                    }
                }


                @Override
                public void onCancelled(DatabaseError databaseError) {
                }
            });
        }

        //db.pavimentoIrregularDAO().deletePavimentos(true);
    }

    protected class TimerTaskToGetLocation extends TimerTask {

        private boolean doStop = false;
        private boolean executandoThread = false;

        public synchronized void doStop() {
            this.doStop = true;
        }

        public synchronized void doRun() {
            this.doStop = false;
        }

        private synchronized void setExecutandoThread(boolean executandoThread){
            this.executandoThread = executandoThread;
        }

        private synchronized boolean getExecutandoThread(){
            return this.executandoThread;
        }

        private synchronized boolean keepRunning() {
            return this.doStop == false;
        }
        @Override
        public void run() {
            while(keepRunning() && !getExecutandoThread()) {
                setExecutandoThread(true);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.e(TAG, "TimerTaskToGetLocation()");
                        updateAddress();
                    }
                });
            }
        }
    }


}