package com.example.pap_findu;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.location.Location;
import android.os.BatteryManager;
import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;

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

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.Priority;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FieldValue;
import com.google.firebase.firestore.FirebaseFirestore;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LocationService extends Service {

    private FusedLocationProviderClient fusedLocationClient;
    private LocationCallback locationCallback;
    private DatabaseReference databaseReference;

    private FirebaseFirestore db;
    private String currentChildCode;
    private List<DocumentSnapshot> activeSafeZones = new ArrayList<>();
    private HashMap<String, Boolean> isInsideZoneMap = new HashMap<>();

    // VARIÁVEIS DE MOVIMENTO INTELIGENTE
    private Location lastCheckLocation = null;
    private long lastCheckTime = 0;
    private boolean isCurrentlyMoving = false;
    private long movementStartTime = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        db = FirebaseFirestore.getInstance();

        currentChildCode = getSharedPreferences("FindU_Prefs", MODE_PRIVATE)
                .getString("child_access_code", null);

        if (currentChildCode != null) {
            databaseReference = FirebaseDatabase.getInstance().getReference(currentChildCode).child("live_location");
            loadSafeZones();
        }
    }

    private void loadSafeZones() {
        db.collection("SafeZones")
                .whereEqualTo("childCode", currentChildCode)
                .addSnapshotListener((value, error) -> {
                    if (value != null) activeSafeZones = value.getDocuments();
                });
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        createNotificationChannel();
        Notification notification = new NotificationCompat.Builder(this, "LocationChannel")
                .setContentTitle("FindU Ativo")
                .setContentText("Monitoramento de segurança em tempo real...")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .build();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
        } else {
            startForeground(1, notification);
        }

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            requestLocationUpdates();
        }

        return START_STICKY;
    }

    private void requestLocationUpdates() {
        LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5000)
                .setMinUpdateIntervalMillis(2000)
                .build();

        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                for (Location location : locationResult.getLocations()) {
                    updateFirebase(location);
                    checkGeofenceMath(location);
                    checkMovementSmartHistory(location);
                }
            }
        };

        try {
            fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
        } catch (SecurityException e) { e.printStackTrace(); }
    }

    // LÓGICA DE MOVIMENTO APERFEIÇOADA (SEM SPAM)
    private void checkMovementSmartHistory(Location currentLocation) {
        long currentTime = System.currentTimeMillis();

        if (lastCheckLocation == null) {
            lastCheckLocation = currentLocation;
            lastCheckTime = currentTime;
            return;
        }

        long elapsedMillis = currentTime - lastCheckTime;

        // VERIFICAÇÃO A CADA 10 MINUTOS (Mude para 1 para testar no emulador)
        if (elapsedMillis >= 10 * 60 * 1000L) {
            float distanceMoved = currentLocation.distanceTo(lastCheckLocation);

            // Se ele se moveu mais de 500 metros desde a última vez
            if (distanceMoved > 500.0f) {
                if (!isCurrentlyMoving) {
                    // ELE COMEÇOU A ANDAR AGORA
                    isCurrentlyMoving = true;
                    movementStartTime = lastCheckTime; // O movimento começou no último checkpoint
                    sendHistoryOnlyEvent("Início de Deslocação", "O filho começou a movimentar-se.");
                }
                // Se já estava a andar, não fazemos nada (para não encher o histórico)
                Log.d("FindU_Move", "Filho continua em movimento...");
            }
            else {
                // ELE ESTÁ PARADO (Moveu menos de 500m)
                if (isCurrentlyMoving) {
                    // ELE ESTAVA A ANDAR E PAROU AGORA
                    isCurrentlyMoving = false;
                    long totalDurationMillis = currentTime - movementStartTime;
                    int totalMinutes = (int) (totalDurationMillis / 60000);

                    sendHistoryOnlyEvent("Fim de Deslocação", "O filho parou. Esteve em movimento por aproximadamente " + totalMinutes + " minutos.");
                } else {
                    // Já estava parado e continua parado... enviamos uma nota apenas se for a primeira vez
                    // Ou podemos simplesmente não enviar nada para manter o histórico limpo
                    Log.d("FindU_Move", "Filho continua parado na mesma zona.");
                }
            }

            // Atualiza o ponto de referência para os próximos 10 minutos
            lastCheckLocation = currentLocation;
            lastCheckTime = currentTime;
        }
    }

    private void checkGeofenceMath(Location currentLocation) {
        if (activeSafeZones == null || currentChildCode == null) return;
        for (DocumentSnapshot zoneDoc : activeSafeZones) {
            String zoneId = zoneDoc.getId();
            Number latNum = (Number) zoneDoc.get("latitude");
            Number lngNum = (Number) zoneDoc.get("longitude");
            Number radNum = (Number) zoneDoc.get("radius");

            if (latNum != null && lngNum != null && radNum != null) {
                Location zoneLoc = new Location("");
                zoneLoc.setLatitude(latNum.doubleValue());
                zoneLoc.setLongitude(lngNum.doubleValue());
                float dist = currentLocation.distanceTo(zoneLoc);
                boolean isInside = dist <= radNum.floatValue();

                if (!isInsideZoneMap.containsKey(zoneId)) {
                    isInsideZoneMap.put(zoneId, isInside);
                    continue;
                }
                if (Boolean.TRUE.equals(isInsideZoneMap.get(zoneId)) && !isInside) {
                    isInsideZoneMap.put(zoneId, false);
                    sendAlert("Saída de Zona", "O filho saiu de uma zona segura.");
                } else if (Boolean.FALSE.equals(isInsideZoneMap.get(zoneId)) && isInside) {
                    isInsideZoneMap.put(zoneId, true);
                    sendAlert("Entrada na Zona", "O filho entrou numa zona segura.");
                }
            }
        }
    }

    private void sendAlert(String title, String message) {
        Map<String, Object> data = new HashMap<>();
        data.put("childCode", currentChildCode);
        data.put("title", title);
        data.put("message", message);
        data.put("timestamp", FieldValue.serverTimestamp());
        data.put("status", "PENDING");
        db.collection("Alerts").add(data);
        db.collection("History").add(data);
    }

    private void sendHistoryOnlyEvent(String title, String message) {
        Map<String, Object> data = new HashMap<>();
        data.put("childCode", currentChildCode);
        data.put("title", title);
        data.put("message", message);
        data.put("timestamp", FieldValue.serverTimestamp());
        data.put("type", "INFO");
        db.collection("History").add(data);
    }

    private void updateFirebase(Location location) {
        if (databaseReference != null) {
            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent batteryStatus = registerReceiver(null, ifilter);
            int level = -1;
            if (batteryStatus != null) {
                level = (int) ((batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) / (float) batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1)) * 100);
            }
            Map<String, Object> data = new HashMap<>();
            data.put("latitude", location.getLatitude());
            data.put("longitude", location.getLongitude());
            data.put("bateria", level + "%");
            data.put("last_updated", System.currentTimeMillis());
            databaseReference.setValue(data);
        }
    }

    @Override public void onDestroy() { super.onDestroy(); }
    @Nullable @Override public IBinder onBind(Intent intent) { return null; }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("LocationChannel", "Monitoramento", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) manager.createNotificationChannel(channel);
        }
    }
}