package com.grigowashere.aismap.controllers;

import android.content.Context;
import android.util.Log;
import com.grigowashere.aismap.models.Vessel;
import com.grigowashere.aismap.models.AISVessel;
import com.grigowashere.aismap.maps.MapInterface;
import com.grigowashere.aismap.data.Repository;
import com.grigowashere.aismap.data.mapper.AISVesselMapper;
import com.grigowashere.aismap.services.NotificationService;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Главный контроллер приложения
 * Координирует работу всех компонентов
 * Использует гибридный подход: координаты через Location API, остальное через NMEA
 */
public class AppController implements 
    NMEAParser.NMEAParserListener,
    UDPListener.UDPListenerCallback,
    AndroidNMEAListener.NMEAMessageCallback,
    GPSLocationListener.LocationCallback,
    MapInterface.MarkerClickListener {
    
    private static final String TAG = "AppController";
    
    private Context context;
    private NMEAParser nmeaParser;
    private UDPListener udpListener;
    private AndroidNMEAListener androidNmeaListener;
    private GPSLocationListener gpsLocationListener;
    private MapInterface mapInterface;
    
    private Vessel ownVessel;
    private List<AISVessel> aisVessels;
    private ExecutorService executor;
    private com.grigowashere.aismap.data.Repository repository;
    private NotificationService notificationService;
    
    private boolean isUDPEnabled;
    private boolean isAndroidNMEAEnabled;
    private boolean isUDPNMEAEnabled;
    private boolean isGPSLocationEnabled;
    private int udpPort;
    private String dataMode;
    
    // Время последнего получения сообщений ($ GPS) и (! AIS) в elapsedRealtime
    private long lastGPSMessageRealtimeMs;
    private long lastAISMessageRealtimeMs;
    
    // Периодическая очистка БД от устаревших AIS целей
    private android.os.Handler dbCleanupHandler;
    private Runnable dbCleanupRunnable;
    private static final long DB_CLEANUP_INTERVAL = 60000; // 1 минута
    
    // Callback для обновления UI
    private UIUpdateCallback uiUpdateCallback;
    
    public interface UIUpdateCallback {
        void onVesselPositionUpdated(Vessel vessel);
        void onGPSQualityUpdated(Vessel vessel);
    }
    
    /**
     * Расширенный интерфейс для дополнительных UI событий
     */
    public interface ExtendedUIUpdateCallback extends UIUpdateCallback {
        void onShowOwnVesselBottomSheet();
        void onShowAISVesselInfo(AISVessel vessel);
        void onUpdateCompass(float azimuth, List<AISVessel> nearbyVessels);
    }
    
    public AppController(Context context) {
        this.context = context;
        this.ownVessel = new Vessel();
        this.aisVessels = new ArrayList<>();
        this.executor = Executors.newCachedThreadPool();
        this.repository = new com.grigowashere.aismap.data.Repository(context);
        this.notificationService = new NotificationService(context);
        
        // Инициализируем Handler для периодической очистки БД
        this.dbCleanupHandler = new android.os.Handler(android.os.Looper.getMainLooper());
        this.dbCleanupRunnable = this::performDatabaseCleanup;
        
        initializeControllers();
    }
    
    /**
     * Инициализирует все контроллеры
     */
    private void initializeControllers() {
        // Инициализация парсера NMEA
        nmeaParser = new NMEAParser();
        nmeaParser.setListener(this);
        
        // Инициализация GPS Location Listener (для координат)
        gpsLocationListener = new GPSLocationListener(context);
        gpsLocationListener.setCallback(this);
        
        // Связываем NMEA парсер с GPS Location Listener для гибридного режима
        nmeaParser.setGPSLocationListener(gpsLocationListener);
        nmeaParser.setHybridMode(true);
        
        // Инициализация UDP слушателя (порт 10110 - стандартный для AIS)
        udpPort = 10110;
        udpListener = new UDPListener(udpPort);
        udpListener.setCallback(this);
        
        // Инициализация Android NMEA слушателя (для курса, скорости, DOP)
        androidNmeaListener = new AndroidNMEAListener(context);
        androidNmeaListener.setCallback(this);

        // Восстанавливаем данные из БД при старте
        try {
            com.grigowashere.aismap.data.entity.VesselEntity latest = repository.getLatestOwnVesselSync();
            if (latest != null) {
                ownVessel.setLatitude(latest.latitude);
                ownVessel.setLongitude(latest.longitude);
                ownVessel.setAccuracy(latest.accuracy);
                ownVessel.setFixTime(latest.fixTime);
            }
            java.util.List<com.grigowashere.aismap.data.entity.AISVesselEntity> list = repository.getAllAISSync();
            if (list != null) {
                for (com.grigowashere.aismap.data.entity.AISVesselEntity entity : list) {
                    // Используем маппер для полного восстановления всех полей
                    AISVessel vessel = AISVesselMapper.toModel(entity);
                    aisVessels.add(vessel);
                    Log.d(TAG, "AIS судно восстановлено из БД с полными данными: " + vessel.getMmsi());
                }
                Log.i(TAG, "Восстановлено " + list.size() + " AIS судов из БД с полными данными");
            }
        } catch (Exception e) {
            Log.e(TAG, "Ошибка восстановления данных из БД: " + e.getMessage(), e);
        }
    }
    
    /**
     * Устанавливает интерфейс карты
     */
    public void setMapInterface(MapInterface mapInterface) {
        Log.i(TAG, "setMapInterface вызван: " + (mapInterface != null ? "mapInterface установлен" : "mapInterface == null"));
        this.mapInterface = mapInterface;
        if (mapInterface != null) {
            Log.i(TAG, "Устанавливаем MarkerClickListener в MapInterface");
            mapInterface.setMarkerClickListener(this);
            Log.i(TAG, "MarkerClickListener установлен, теперь можно создавать маркеры");

            // Восстановление отрисовки сохранённых данных на карте
            new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                try {
                    // Позиция нашего судна
                    if (ownVessel != null && ownVessel.getLatitude() != 0 && ownVessel.getLongitude() != 0) {
                        mapInterface.updateOwnVesselPosition(ownVessel);
                    }
                    // AIS маркеры
                    if (aisVessels != null && !aisVessels.isEmpty()) {
                        for (AISVessel v : aisVessels) {
                            mapInterface.addAISVesselMarker(v);
                        }
                    }
                } catch (Exception e) {
                    Log.e(TAG, "Ошибка восстановления отрисовки на карте: " + e.getMessage(), e);
                }
            });
        }
    }
    
    /**
     * Устанавливает callback для обновления UI
     */
    public void setUIUpdateCallback(UIUpdateCallback callback) {
        this.uiUpdateCallback = callback;
    }
    
    /**
     * Запускает все слушатели
     */
    public void startAllListeners() {
        // GPS Location Listener запускается в главном потоке
        if (isGPSLocationEnabled) {
            gpsLocationListener.startListening();
        }
        
        // Android NMEA слушатель должен запускаться в главном потоке
        if (isAndroidNMEAEnabled) {
            androidNmeaListener.startListening();
        }
        
        // UDP слушатель запускается в фоновом потоке
        if (isUDPEnabled) {
            executor.execute(() -> {
                udpListener.start();
            });
        }
        
        // Запускаем периодическую очистку БД от устаревших AIS целей
        startDatabaseCleanup();
    }
    

    
    /**
     * Останавливает все слушатели
     */
    public void stopAllListeners() {
        // Останавливаем периодическую очистку БД
        stopDatabaseCleanup();
        
        executor.execute(() -> {
            udpListener.stop();
            androidNmeaListener.stopListening();
            gpsLocationListener.stopListening();
        });
    }
    
    /**
     * Включает/выключает UDP слушатель
     */
    public void setUDPEnabled(boolean enabled) {
        this.isUDPEnabled = enabled;
        if (enabled && !udpListener.isRunning()) {
            udpListener.start();
        } else if (!enabled && udpListener.isRunning()) {
            udpListener.stop();
        }
    }
    
    /**
     * Включает/выключает Android NMEA слушатель
     */
    public void setAndroidNMEAEnabled(boolean enabled) {
        Log.i(TAG, "🔄 setAndroidNMEAEnabled: " + enabled);
        this.isAndroidNMEAEnabled = enabled;
        
        // Android NMEA слушатель управляется в главном потоке
        if (enabled && !androidNmeaListener.isListening()) {
            Log.i(TAG, "🚀 Запускаем Android NMEA слушатель...");
            boolean success = androidNmeaListener.startListening();
            if (success) {
                Log.i(TAG, "✅ Android NMEA слушатель успешно запущен");
            } else {
                Log.e(TAG, "❌ Не удалось запустить Android NMEA слушатель");
            }
        } else if (!enabled && androidNmeaListener.isListening()) {
            Log.i(TAG, "⏹️ Останавливаем Android NMEA слушатель...");
            androidNmeaListener.stopListening();
        }
    }
    
    /**
     * Включает/выключает GPS Location слушатель
     */
    public void setGPSLocationEnabled(boolean enabled) {
        Log.i(TAG, "🔄 setGPSLocationEnabled: " + enabled);
        this.isGPSLocationEnabled = enabled;
        
        if (enabled && !gpsLocationListener.isListening()) {
            Log.i(TAG, "🚀 Запускаем GPS Location слушатель...");
            boolean success = gpsLocationListener.startListening();
            if (success) {
                Log.i(TAG, "✅ GPS Location слушатель успешно запущен");
            } else {
                Log.e(TAG, "❌ Не удалось запустить GPS Location слушатель");
            }
        } else if (!enabled && gpsLocationListener.isListening()) {
            Log.i(TAG, "⏹️ Останавливаем GPS Location слушатель...");
            gpsLocationListener.stopListening();
        }
    }
    

    
    /**
     * Отправляет данные по UDP
     */
    public void sendUDPData(String data, String address, int port) {
        udpListener.sendData(data, address, port);
    }
    
    /**
     * Проверяет, включен ли UDP слушатель
     */
    public boolean isUDPEnabled() {
        return isUDPEnabled;
    }
    
    /**
     * Проверяет, включен ли Android NMEA слушатель
     */
    public boolean isAndroidNMEAEnabled() {
        return isAndroidNMEAEnabled;
    }
    
    /**
     * Проверяет, включен ли GPS Location слушатель
     */
    public boolean isGPSLocationEnabled() {
        return isGPSLocationEnabled;
    }
    
    /**
     * Обновляет данные нашего судна при клике по маркеру
     */
    private void updateOwnVesselData(Vessel vessel) {
        if (vessel != null) {
            // Обновляем только те данные, которые могут быть актуальными
            // Координаты и основная информация уже обновляются через GPS
            if (vessel.getCourse() > 0) {
                ownVessel.setCourse(vessel.getCourse());
                updateCompass(); // Обновляем компас при изменении курса
            }
            if (vessel.getSpeed() > 0) {
                ownVessel.setSpeed(vessel.getSpeed());
            }
            if (vessel.getSatellites() > 0) {
                ownVessel.setSatellites(vessel.getSatellites());
            }
            if (vessel.getAltitude() != 0) {
                ownVessel.setAltitude(vessel.getAltitude());
            }
            if (vessel.getPdop() > 0) {
                ownVessel.setPdop(vessel.getPdop());
                ownVessel.setHdop(vessel.getHdop());
                ownVessel.setVdop(vessel.getVdop());
            }
        }
    }
    
    // Реализация LocationCallback (GPS Location Listener)
    
    @Override
    public void onLocationUpdated(Vessel vessel) {
        Log.i(TAG, "📍 GPS Location обновлен: lat=" + vessel.getLatitude() + 
              ", lon=" + vessel.getLongitude() + 
              ", accuracy=" + vessel.getAccuracy() + "м");
        
        // Обновляем координаты нашего судна
        ownVessel.setLatitude(vessel.getLatitude());
        ownVessel.setLongitude(vessel.getLongitude());
        ownVessel.setAccuracy(vessel.getAccuracy());
        ownVessel.setFixTime(vessel.getFixTime());
        ownVessel.setFixQuality(vessel.getFixQuality());
        
        // Сохраняем позицию в локальную БД
        try {
            com.grigowashere.aismap.data.entity.VesselEntity ve = new com.grigowashere.aismap.data.entity.VesselEntity();
            ve.latitude = ownVessel.getLatitude();
            ve.longitude = ownVessel.getLongitude();
            ve.accuracy = ownVessel.getAccuracy();
            ve.fixTime = ownVessel.getFixTime();
            repository.upsertOwnVessel(ve);
        } catch (Exception e) {
            Log.e(TAG, "Ошибка сохранения позиции в БД: " + e.getMessage(), e);
        }

        // Обновляем UI через callback
        if (uiUpdateCallback != null) {
            uiUpdateCallback.onVesselPositionUpdated(ownVessel);
        }
        
        // Обновляем карту в главном потоке с throttling
        if (mapInterface != null) {
            Log.i(TAG, "Обновляем позицию на карте...");
            // Используем postDelayed для предотвращения частых обновлений
            new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> {
                try {
                    Log.i(TAG, "Вызываем mapInterface.updateOwnVesselPosition...");
                    mapInterface.updateOwnVesselPosition(ownVessel);
                    Log.i(TAG, "Позиция на карте обновлена");
                } catch (Exception e) {
                    Log.e(TAG, "Ошибка обновления позиции на карте: " + e.getMessage(), e);
                }
            }, 100); // Задержка 100мс для throttling
        }
    }
    
    @Override
    public void onGPSStatusChanged(int status) {
        Log.i(TAG, "GPS статус изменился: " + status);
    }
    
    // Реализация NMEAParserListener
    
    @Override
    public void onVesselUpdated(Vessel vessel) {
        Log.i(TAG, "🔄 onVesselUpdated вызван: lat=" + vessel.getLatitude() + 
              ", lon=" + vessel.getLongitude() + 
              ", course=" + vessel.getCourse() + 
              ", speed=" + vessel.getSpeed());
        
        // Обновляем координаты, если они есть (для режима "только NMEA")
        if (vessel.getLatitude() != 0 && vessel.getLongitude() != 0) {
            ownVessel.setLatitude(vessel.getLatitude());
            ownVessel.setLongitude(vessel.getLongitude());
            Log.i(TAG, "📍 Координаты обновлены из NMEA: lat=" + vessel.getLatitude() + 
                  ", lon=" + vessel.getLongitude());
        }
        
        // Обновляем дополнительные данные
        if (vessel.getCourse() > 0) {
            ownVessel.setCourse(vessel.getCourse());
            updateCompass(); // Обновляем компас при изменении курса
        }
        if (vessel.getSpeed() > 0) {
            ownVessel.setSpeed(vessel.getSpeed());
        }
        if (vessel.getSatellites() > 0) {
            ownVessel.setSatellites(vessel.getSatellites());
        }
        if (vessel.getAltitude() != 0) {
            ownVessel.setAltitude(vessel.getAltitude());
        }
        
        Log.i(TAG, "NMEA данные обновлены: course=" + vessel.getCourse() + 
              ", speed=" + vessel.getSpeed() + 
              ", satellites=" + vessel.getSatellites());
        
        // Обновляем карту в главном потоке
        if (mapInterface != null) {
            Log.i(TAG, "Обновляем позицию на карте из NMEA...");
            new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                try {
                    Log.i(TAG, "Вызываем mapInterface.updateOwnVesselPosition из NMEA...");
                    mapInterface.updateOwnVesselPosition(ownVessel);
                    Log.i(TAG, "Позиция на карте обновлена из NMEA");
                } catch (Exception e) {
                    Log.e(TAG, "Ошибка обновления позиции на карте из NMEA: " + e.getMessage(), e);
                }
            });
        }
        
        // Обновляем UI
        if (uiUpdateCallback != null) {
            uiUpdateCallback.onVesselPositionUpdated(ownVessel);
        }
    }
    
    @Override
    public void onDOPUpdated(double pdop, double hdop, double vdop) {
        Log.i(TAG, "📊 DOP обновлен: PDOP=" + pdop + ", HDOP=" + hdop + ", VDOP=" + vdop);
        
        // Обновляем DOP значения
        ownVessel.setPdop(pdop);
        ownVessel.setHdop(hdop);
        ownVessel.setVdop(vdop);
        
        // Обновляем UI
        if (uiUpdateCallback != null) {
            uiUpdateCallback.onGPSQualityUpdated(ownVessel);
        }
    }
    
    @Override
    public void onAISVesselUpdated(AISVessel vessel) {
        // Проверяем, есть ли уже такое судно
        AISVessel existingVessel = findAISVesselByMMSI(vessel.getMmsi());
        
        if (existingVessel != null) {
            // Если пришло новое safety-сообщение (тип 14), уведомим пользователя
            if (vessel.getLastSafetyMessage() != null && !vessel.getLastSafetyMessage().isEmpty()) {
                String prev = existingVessel.getLastSafetyMessage();
                String curr = vessel.getLastSafetyMessage();
                if (prev == null || !prev.equals(curr)) {
                    if (notificationService != null && notificationService.areNotificationsEnabled()) {
                        notificationService.notifySafetyMessage(vessel.getMmsi(), curr);
                    }
                }
                existingVessel.setLastSafetyMessage(curr);
            }
            // Обновляем существующее судно
            existingVessel.updatePosition(
                vessel.getLatitude(), 
                vessel.getLongitude(), 
                vessel.getCourse(), 
                vessel.getSpeed()
            );
            try {
                // Используем маппер для полной конвертации всех полей
                com.grigowashere.aismap.data.entity.AISVesselEntity entity = AISVesselMapper.toEntity(existingVessel);
                repository.upsertAIS(entity);
                Log.d(TAG, "AIS судно сохранено в БД с полными данными: " + existingVessel.getMmsi());
            } catch (Exception e) {
                Log.e(TAG, "Ошибка апсерта AIS в БД: " + e.getMessage(), e);
            }
            
            if (mapInterface != null) {
                // Используем Handler для выполнения в главном потоке
                new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                    try {
                        mapInterface.updateAISVesselPosition(existingVessel);
                    } catch (Exception e) {
                        Log.e(TAG, "Ошибка обновления позиции AIS судна на карте: " + e.getMessage(), e);
                    }
                });
            }
        } else {
            // Добавляем новое судно
            aisVessels.add(vessel);

            // Если это новое судно сразу пришло с safety-сообщением — уведомим
            if (vessel.getLastSafetyMessage() != null && !vessel.getLastSafetyMessage().isEmpty()) {
                if (notificationService != null && notificationService.areNotificationsEnabled()) {
                    notificationService.notifySafetyMessage(vessel.getMmsi(), vessel.getLastSafetyMessage());
                }
            }
            
            // Воспроизводим уведомление о новой цели
            if (notificationService != null && notificationService.areNotificationsEnabled()) {
                notificationService.notifyNewAISTarget();
                Log.i(TAG, "🔔 Уведомление о новой AIS цели: " + vessel.getMmsi());
            }
            
            try {
                // Используем маппер для полной конвертации всех полей
                com.grigowashere.aismap.data.entity.AISVesselEntity entity = AISVesselMapper.toEntity(vessel);
                repository.upsertAIS(entity);
                Log.d(TAG, "Новое AIS судно сохранено в БД с полными данными: " + vessel.getMmsi());
            } catch (Exception e) {
                Log.e(TAG, "Ошибка апсерта AIS в БД: " + e.getMessage(), e);
            }
            
            if (mapInterface != null) {
                // Используем Handler для выполнения в главном потоке
                new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                    try {
                        mapInterface.addAISVesselMarker(vessel);
                    } catch (Exception e) {
                        Log.e(TAG, "Ошибка добавления AIS судна на карту: " + e.getMessage(), e);
                    }
                });
            }
        }
        
        // Обновляем компас с ближайшими судами
        updateCompass();
        
        Log.i(TAG, "AIS судно обновлено: " + vessel);
    }
    
    @Override
    public void onParseError(String error) {
        Log.e(TAG, "Ошибка парсинга NMEA: " + error);
    }
    
    /**
     * Обновляет компас с текущим азимутом и ближайшими судами
     */
    private void updateCompass() {
        if (uiUpdateCallback instanceof ExtendedUIUpdateCallback) {
            float azimuth = (float) ownVessel.getCourse();
            List<AISVessel> nearbyVessels = getNearbyVessels();
            
            new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                ((ExtendedUIUpdateCallback) uiUpdateCallback).onUpdateCompass(azimuth, nearbyVessels);
            });
        }
    }
    
    /**
     * Получает список ближайших судов (в пределах 10 км)
     */
    private List<AISVessel> getNearbyVessels() {
        List<AISVessel> nearby = new ArrayList<>();
        double maxDistance = 10000; // 10 км в метрах
        
        for (AISVessel vessel : aisVessels) {
            double distance = com.grigowashere.aismap.utils.GeoUtils.calculateDistance(ownVessel, vessel);
            if (distance <= maxDistance) {
                nearby.add(vessel);
            }
        }
        
        return nearby;
    }
    
    // Реализация UDPListenerCallback
    
    @Override
    public void onDataReceived(String data, String sourceAddress, int sourcePort) {
        Log.d(TAG, "UDP данные получены от " + sourceAddress + ":" + sourcePort);
        
        // Парсим полученные данные как NMEA
        nmeaParser.parseNMEA(data);
        // Обновляем метки времени по префиксу
        updateLastMessageAgesFromRaw(data);
    }
    
    @Override
    public void onUDPError(String error) {
        Log.e(TAG, "UDP ошибка: " + error);
    }
    
    @Override
    public void onError(String error) {
        Log.e(TAG, "GPS Location ошибка: " + error);
    }
    
    // Реализация NMEAMessageCallback
    
    @Override
    public void onNMEAMessage(String message, long timestamp) {
        Log.i(TAG, "📱 Android NMEA сообщение получено в AppController: " + message);
        
        // Парсим полученные данные как NMEA
        nmeaParser.parseNMEA(message);
        if (message != null) {
            String trimmed = message.trim();
            if (!trimmed.isEmpty()) {
                char c = trimmed.charAt(0);
                long now = android.os.SystemClock.elapsedRealtime();
                if (c == '$') {
                    lastGPSMessageRealtimeMs = now;
                } else if (c == '!') {
                    lastAISMessageRealtimeMs = now;
                }
            }
        }
    }
    
    // Реализация MarkerClickListener
    
    @Override
    public void onOwnVesselClick(Vessel vessel) {
        Log.i(TAG, "Клик по нашему судну: " + vessel);
        // Уведомляем UI о необходимости показать BottomSheet
        if (uiUpdateCallback != null) {
            Log.i(TAG, "uiUpdateCallback найден, обновляем данные судна");
            // Обновляем данные судна перед показом
            updateOwnVesselData(vessel);
            // Вызываем специальный callback для показа BottomSheet
            if (uiUpdateCallback instanceof ExtendedUIUpdateCallback) {
                Log.i(TAG, "Вызываем onShowOwnVesselBottomSheet");
                ((ExtendedUIUpdateCallback) uiUpdateCallback).onShowOwnVesselBottomSheet();
            } else {
                Log.w(TAG, "uiUpdateCallback не является ExtendedUIUpdateCallback");
            }
        } else {
            Log.e(TAG, "uiUpdateCallback == null!");
        }
    }
    
    @Override
    public void onAISVesselClick(AISVessel vessel) {
        Log.i(TAG, "Клик по AIS судну: " + vessel);
        // Уведомляем UI о необходимости показать информацию об AIS судне
        if (uiUpdateCallback != null && uiUpdateCallback instanceof ExtendedUIUpdateCallback) {
            ((ExtendedUIUpdateCallback) uiUpdateCallback).onShowAISVesselInfo(vessel);
        }
    }
    
    /**
     * Находит AIS судно по MMSI
     */
    private AISVessel findAISVesselByMMSI(String mmsi) {
        for (AISVessel vessel : aisVessels) {
            if (mmsi.equals(vessel.getMmsi())) {
                return vessel;
            }
        }
        return null;
    }
    
    /**
     * Получает наше судно
     */
    public Vessel getOwnVessel() {
        return ownVessel;
    }
    
    /**
     * Получает список AIS судов
     */
    public List<AISVessel> getAISVessels() {
        return new ArrayList<>(aisVessels);
    }
    
    /**
     * Очищает все AIS суда
     */
    public void clearAISVessels() {
        aisVessels.clear();
        if (mapInterface != null) {
            // Используем Handler для выполнения в главном потоке
            new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                try {
                    mapInterface.clearAISVesselMarkers();
                } catch (Exception e) {
                    Log.e(TAG, "Ошибка очистки AIS судов на карте: " + e.getMessage(), e);
                }
            });
        }
    }
    
    /**
     * Центрирует карту на позиции нашего судна
     */
    public void centerOnOwnVessel() {
        if (mapInterface != null && ownVessel != null) {
            // Используем Handler для выполнения в главном потоке
            new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
                try {
                    mapInterface.centerOnPosition(ownVessel.getLatitude(), ownVessel.getLongitude());
                } catch (Exception e) {
                    Log.e(TAG, "Ошибка центрирования карты: " + e.getMessage(), e);
                }
            });
        }
    }
    
    /**
     * Запускает периодическую очистку БД от устаревших AIS целей
     */
    public void startDatabaseCleanup() {
        if (dbCleanupHandler != null && dbCleanupRunnable != null) {
            dbCleanupHandler.postDelayed(dbCleanupRunnable, DB_CLEANUP_INTERVAL);
            Log.i(TAG, "Запущена периодическая очистка БД от устаревших AIS целей");
        }
    }
    
    /**
     * Останавливает периодическую очистку БД
     */
    public void stopDatabaseCleanup() {
        if (dbCleanupHandler != null && dbCleanupRunnable != null) {
            dbCleanupHandler.removeCallbacks(dbCleanupRunnable);
            Log.i(TAG, "Остановлена периодическая очистка БД от устаревших AIS целей");
        }
    }
    
    /**
     * Выполняет очистку БД от устаревших AIS целей
     */
    private void performDatabaseCleanup() {
        try {
            com.grigowashere.aismap.utils.SettingsManager settingsManager = 
                new com.grigowashere.aismap.utils.SettingsManager(context);
            
            int staleRemoveMinutes = settingsManager.getDataStaleRemoveMinutes();
            long thresholdEpochMs = System.currentTimeMillis() - (staleRemoveMinutes * 60 * 1000L);
            
            repository.deleteStaleAIS(thresholdEpochMs);
            
            Log.i(TAG, "Выполнена очистка БД от AIS целей старше " + staleRemoveMinutes + " минут");
            
            // Планируем следующую очистку
            if (dbCleanupHandler != null && dbCleanupRunnable != null) {
                dbCleanupHandler.postDelayed(dbCleanupRunnable, DB_CLEANUP_INTERVAL);
            }
        } catch (Exception e) {
            Log.e(TAG, "Ошибка при очистке БД от устаревших AIS целей: " + e.getMessage(), e);
        }
    }
    
    /**
     * Освобождает ресурсы
     */
    public void cleanup() {
        stopAllListeners();
        stopDatabaseCleanup();
        
        if (udpListener != null) {
            udpListener.cleanup();
        }
        
        if (androidNmeaListener != null) {
            androidNmeaListener.cleanup();
        }
        
        if (gpsLocationListener != null) {
            gpsLocationListener.cleanup();
        }
        
        if (notificationService != null) {
            notificationService.cleanup();
        }
        
        if (executor != null && !executor.isShutdown()) {
            executor.shutdown();
        }
    }
    
    // ===== Метки времени последних сообщений ($ и !) =====
    private void updateLastMessageAgesFromRaw(String raw) {
        if (raw == null) return;
        long now = android.os.SystemClock.elapsedRealtime();
        String[] lines = raw.split("\r?\n");
        for (String line : lines) {
            if (line == null) continue;
            String t = line.trim();
            if (t.isEmpty()) continue;
            char c = t.charAt(0);
            if (c == '$') {
                lastGPSMessageRealtimeMs = now;
                break;
            } else if (c == '!') {
                lastAISMessageRealtimeMs = now;
                break;
            }
        }
    }

    /** Возвращает секунды с последнего GPS ($) сообщения; -1 если не было */
    public int getSecondsSinceLastGPSMessage() {
        if (lastGPSMessageRealtimeMs <= 0) return -1;
        long diff = android.os.SystemClock.elapsedRealtime() - lastGPSMessageRealtimeMs;
        if (diff < 0) return 0;
        return (int)(diff / 1000L);
    }

    /** Возвращает секунды с последнего AIS (!) сообщения; -1 если не было */
    public int getSecondsSinceLastAISMessage() {
        if (lastAISMessageRealtimeMs <= 0) return -1;
        long diff = android.os.SystemClock.elapsedRealtime() - lastAISMessageRealtimeMs;
        if (diff < 0) return 0;
        return (int)(diff / 1000L);
    }
    
    // Методы для управления настройками
    
    /**
     * Устанавливает UDP порт
     */
    public void setUDPPort(int port) {
        if (port < 1 || port > 65535) {
            Log.w(TAG, "Некорректный UDP порт: " + port);
            return;
        }
        
        this.udpPort = port;
        Log.i(TAG, "UDP порт установлен: " + port);
        
        // Если UDP слушатель уже создан, нужно будет его пересоздать
        if (udpListener != null && udpListener.getPort() != port) {
            Log.i(TAG, "UDP порт изменен, потребуется перезапуск UDP слушателя");
        }
    }
    
    /**
     * Получает текущий UDP порт
     */
    public int getUDPPort() {
        return udpPort;
    }
    
    /**
     * Включает/выключает UDP NMEA
     */
    public void setUDPNMEAEnabled(boolean enabled) {
        this.isUDPNMEAEnabled = enabled;
        Log.i(TAG, "UDP NMEA: " + (enabled ? "включен" : "выключен"));
    }
    
    /**
     * Проверяет, включен ли UDP NMEA
     */
    public boolean isUDPNMEAEnabled() {
        return isUDPNMEAEnabled;
    }
    
    /**
     * Устанавливает режим работы с данными
     */
    public void setDataMode(String mode) {
        this.dataMode = mode;
        Log.i(TAG, "🔄 Режим данных установлен: " + mode);
        
        // Применяем режим к NMEA парсеру
        if (nmeaParser != null) {
            boolean hybridMode = "hybrid".equals(mode);
            nmeaParser.setHybridMode(hybridMode);
            Log.i(TAG, "📍 Гибридный режим NMEA парсера: " + hybridMode);
            Log.i(TAG, "📍 В режиме '" + mode + "' координаты будут " + 
                  (hybridMode ? "браться из Android GPS API" : "браться из NMEA сообщений"));
        }
    }
    
    /**
     * Получает текущий режим работы с данными
     */
    public String getDataMode() {
        return dataMode;
    }
    
    /**
     * Перезапускает UDP слушатель с новым портом
     */
    public void restartUDPListener() {
        if (udpListener != null) {
            Log.i(TAG, "Перезапускаем UDP слушатель с портом: " + udpPort);
            
            // Останавливаем текущий слушатель
            udpListener.stop();
            udpListener.cleanup();
            
            // Создаем новый слушатель с новым портом
            udpListener = new UDPListener(udpPort);
            udpListener.setCallback(this);
            
            // Запускаем, если UDP включен
            if (isUDPEnabled) {
                udpListener.start();
                Log.i(TAG, "UDP слушатель перезапущен на порту: " + udpPort);
            }
        }
    }
    
    /**
     * Получает статус всех настроек
     */
    public String getSettingsStatus() {
        return String.format(
            "UDP: порт=%d, включен=%s, NMEA=%s\n" +
            "Android NMEA: %s\n" +
            "GPS Location: %s\n" +
            "Режим данных: %s",
            udpPort,
            isUDPEnabled ? "да" : "нет",
            isUDPNMEAEnabled ? "включен" : "выключен",
            isAndroidNMEAEnabled ? "включен" : "выключен",
            isGPSLocationEnabled ? "включен" : "выключен",
            dataMode != null ? dataMode : "не установлен"
        );
    }
}
