package br.com.localizacelularweb.localizador;

import android.Manifest;
import android.app.*;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Handler;
import android.os.Looper;

import org.json.JSONObject;

import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class LocationService extends Service implements LocationListener {

    private static final String CHANNEL_ID = "localizador_localizacao";
    private static final int NOTIFICATION_ID = 100;
    private static final String PREFS = "localizador";

    private LocationManager locationManager;
    private SharedPreferences prefs;
    private String token;
    private final Handler comandoHandler = new Handler(Looper.getMainLooper());
    private boolean consultaComandoAtiva = false;
    private int solicitacaoPendenteId = 0;

    private final Runnable comandoRunnable = new Runnable() {
        @Override
        public void run() {
            consultarComandoAtualizacao();
            if (consultaComandoAtiva) {
                comandoHandler.postDelayed(this, 15000L);
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();

        // IMPORTANTE: usa o MESMO SharedPreferences da MainActivity.
        prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
        criarCanal();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent != null) {
            String tokenIntent = intent.getStringExtra("token");
            if (tokenIntent != null && !tokenIntent.trim().isEmpty()) {
                token = tokenIntent;
                prefs.edit().putString("token", token).apply();
            }
        }

        if (token == null || token.trim().isEmpty()) {
            token = prefs.getString("token", "");
        }

        // Em uma recriação automática do serviço, só continua se o usuário
        // não tiver pressionado o botão PARAR.
        boolean deveContinuar = prefs.getBoolean("compartilhamento_ativo", false);

        if (!deveContinuar) {
            prefs.edit().putBoolean("servico_ativo", false).apply();
            stopSelf();
            return START_NOT_STICKY;
        }

        iniciarForeground();
        iniciarGps();

        prefs.edit().putBoolean("servico_ativo", true).apply();
        iniciarConsultaComandos();

        // Solicita ao Android a recriação do serviço caso o processo seja
        // encerrado por falta de memória. A preferência acima define se deve voltar.
        return START_STICKY;
    }

    private void criarCanal() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "Localização",
                    NotificationManager.IMPORTANCE_LOW
            );

            channel.setDescription("Aviso enquanto o compartilhamento de localização estiver ativo.");
            channel.setSound(null, null);
            channel.enableVibration(false);
            channel.enableLights(false);
            channel.setShowBadge(false);

            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
    }

    private void iniciarForeground() {
        Intent abrirIntent = new Intent(this, MainActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                abrirIntent,
                Build.VERSION.SDK_INT >= 23
                        ? PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
                        : PendingIntent.FLAG_UPDATE_CURRENT
        );

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(android.R.drawable.ic_menu_mylocation)
                .setContentTitle("Localizador")
                .setContentText("Compartilhamento de localização ativo")
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setSilent(true)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(NOTIFICATION_ID, notification);
    }

    private void iniciarGps() {
        if (locationManager != null) {
            try {
                locationManager.removeUpdates(this);
            } catch (Exception ignored) {}
        }

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        if (locationManager == null) return;

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
            prefs.edit()
                    .putBoolean("compartilhamento_ativo", false)
                    .putBoolean("servico_ativo", false)
                    .apply();
            stopSelf();
            return;
        }

        try {
            locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    30000L,
                    5f,
                    this
            );
        } catch (Exception ignored) {}

        try {
            locationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    30000L,
                    10f,
                    this
            );
        } catch (Exception ignored) {}
    }


    private void iniciarConsultaComandos() {
        if (consultaComandoAtiva) return;
        consultaComandoAtiva = true;
        comandoHandler.removeCallbacks(comandoRunnable);
        comandoHandler.post(comandoRunnable);
    }

    private void consultarComandoAtualizacao() {
        if (token == null || token.trim().isEmpty()) return;
        if (!prefs.getBoolean("compartilhamento_ativo", false)) return;

        Map<String, String> dados = new HashMap<>();
        dados.put("token", token);

        HttpHelper.postForm(
                BuildConfig.BASE_URL + "api/comando_localizacao.php",
                dados,
                (okHttp, body) -> {
                    if (!okHttp) return;
                    try {
                        JSONObject obj = new JSONObject(body);
                        if (!obj.optBoolean("ok", false)) return;
                        if (!obj.optBoolean("solicitar", false)) return;

                        int id = obj.optInt("solicitacao_id", 0);
                        if (id <= 0 || id == solicitacaoPendenteId) return;

                        solicitacaoPendenteId = id;
                        solicitarLeituraImediata();
                    } catch (Exception ignored) {}
                }
        );
    }

    private void solicitarLeituraImediata() {
        if (locationManager == null) {
            iniciarGps();
        }
        if (locationManager == null) return;

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        boolean solicitou = false;
        try {
            if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, Looper.getMainLooper());
                solicitou = true;
            }
        } catch (Exception ignored) {}

        if (!solicitou) {
            try {
                if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
                    locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, this, Looper.getMainLooper());
                    solicitou = true;
                }
            } catch (Exception ignored) {}
        }

        if (!solicitou) {
            Location ultima = null;
            try { ultima = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); } catch (Exception ignored) {}
            if (ultima == null) {
                try { ultima = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } catch (Exception ignored) {}
            }
            if (ultima != null) enviarLocalizacao(ultima);
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        // Uma verificação adicional impede envio depois que o próprio usuário parar.
        if (!prefs.getBoolean("compartilhamento_ativo", false)) {
            stopSelf();
            return;
        }
        enviarLocalizacao(location);
    }

    private void enviarLocalizacao(Location location) {
        if (token == null || token.trim().isEmpty()) return;

        Map<String, String> dados = new HashMap<>();
        dados.put("token", token);
        dados.put("latitude", String.valueOf(location.getLatitude()));
        dados.put("longitude", String.valueOf(location.getLongitude()));
        dados.put("precisao", String.valueOf(location.getAccuracy()));
        if (solicitacaoPendenteId > 0) {
            dados.put("solicitacao_id", String.valueOf(solicitacaoPendenteId));
        }

        if (location.hasSpeed()) {
            dados.put("velocidade", String.valueOf(location.getSpeed()));
        }

        BatteryManager bm = (BatteryManager) getSystemService(BATTERY_SERVICE);
        if (bm != null && Build.VERSION.SDK_INT >= 21) {
            int bateria = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
            if (bateria >= 0 && bateria <= 100) {
                dados.put("bateria", String.valueOf(bateria));
            }
        }

        HttpHelper.postForm(
                BuildConfig.BASE_URL + "api/localizacao.php",
                dados,
                (okHttp, body) -> {
                    if (okHttp && HttpHelper.jsonOk(body)) {
                        solicitacaoPendenteId = 0;
                        String data = new SimpleDateFormat(
                                "dd/MM/yyyy HH:mm:ss",
                                Locale.getDefault()
                        ).format(new Date());

                        String ultima =
                                "Último envio: " + data +
                                "\nLatitude: " + location.getLatitude() +
                                "\nLongitude: " + location.getLongitude() +
                                "\nPrecisão: " + Math.round(location.getAccuracy()) + " m";

                        prefs.edit()
                                .putString("ultima_localizacao", ultima)
                                .putBoolean("servico_ativo", true)
                                .apply();
                    }
                }
        );
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);

        // Remover o app da tela de recentes NÃO equivale a apertar PARAR.
        // Reforça o serviço foreground quando o compartilhamento foi autorizado.
        if (prefs != null && prefs.getBoolean("compartilhamento_ativo", false)) {
            try {
                Intent reiniciar = new Intent(getApplicationContext(), LocationService.class);
                reiniciar.putExtra("token", prefs.getString("token", ""));
                ContextCompat.startForegroundService(getApplicationContext(), reiniciar);
            } catch (Exception ignored) {
                // START_STICKY ainda permite ao sistema recriar o serviço posteriormente.
            }
        }
    }

    @Override
    public void onDestroy() {
        consultaComandoAtiva = false;
        comandoHandler.removeCallbacks(comandoRunnable);

        if (locationManager != null) {
            try {
                locationManager.removeUpdates(this);
            } catch (Exception ignored) {}
        }

        // Não desliga a preferência do usuário aqui. onDestroy também pode ser
        // chamado pelo próprio Android. Somente o botão PARAR limpa essa preferência.
        if (prefs != null) {
            prefs.edit().putBoolean("servico_ativo", false).apply();
        }

        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override public void onProviderEnabled(String provider) {}
    @Override public void onProviderDisabled(String provider) {}
    @Override public void onStatusChanged(String provider, int status, Bundle extras) {}
}
