package com.grigowashere.aismap.maps;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.grigowashere.aismap.models.Vessel;
import com.grigowashere.aismap.models.AISVessel;
import com.yandex.mapkit.map.MapObjectCollection;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Менеджер маркеров для Yandex Maps
 * Управляет жизненным циклом маркеров и предотвращает их финализацию
 */
public class YandexMarkerManager implements MarkerManager {
    
    private static final String TAG = "YandexMarkerManager";
    
    private Context context;
    private MapObjectCollection mapObjects;
    private com.yandex.mapkit.mapview.MapView mapView;
    private MapInterface.MarkerClickListener markerClickListener;
    private com.grigowashere.aismap.utils.SettingsManager settingsManager;
    
    // Кеш маркеров с управлением жизненным циклом
    private Map<String, YandexMarkerWrapper> markerCache = new ConcurrentHashMap<>();
    private YandexMarkerWrapper ownVesselMarker;
    
    // Трекеры путей движения судов
    private Map<String, VesselPathTracker> pathTrackers = new ConcurrentHashMap<>();
    private VesselPathTracker ownVesselPathTracker;
    private boolean pathTrackingEnabled = true;
    
    // Периодическая очистка устаревших маркеров
    private Handler cleanupHandler;
    private Runnable cleanupRunnable;
    private static final long CLEANUP_INTERVAL = 10000; // 10 секунд
    
    // Периодическое обновление маркеров для предотвращения финализации
    private Handler refreshHandler;
    private Runnable refreshRunnable;
    private static final long REFRESH_INTERVAL = 2000; // 2 секунды
    
    public YandexMarkerManager(Context context, MapObjectCollection mapObjects, com.yandex.mapkit.mapview.MapView mapView, com.grigowashere.aismap.utils.SettingsManager settingsManager) {
        this.context = context;
        this.mapObjects = mapObjects;
        this.mapView = mapView;
        this.settingsManager = settingsManager;
        this.cleanupHandler = new Handler(Looper.getMainLooper());
        this.refreshHandler = new Handler(Looper.getMainLooper());
    }
    
    @Override
    public void initialize() {
        startPeriodicCleanup();
        startPeriodicRefresh();
        
        // Инициализируем настройки путей из SettingsManager
        if (settingsManager != null) {
            pathTrackingEnabled = settingsManager.isPathTrackingEnabled();
            updatePathSettings(
                settingsManager.getPathColor(),
                settingsManager.getPredictionColor(),
                settingsManager.getPathWidth(),
                settingsManager.getPredictionWidth()
            );
        }
    }
    
    @Override
    public void cleanup() {
        stopPeriodicCleanup();
        stopPeriodicRefresh();
        
        // Удаляем все маркеры
        for (YandexMarkerWrapper marker : markerCache.values()) {
            marker.remove();
        }
        markerCache.clear();
        
        if (ownVesselMarker != null) {
            ownVesselMarker.remove();
            ownVesselMarker = null;
        }
        
        // Очищаем трекеры путей
        for (VesselPathTracker tracker : pathTrackers.values()) {
            tracker.remove();
        }
        pathTrackers.clear();
        
        if (ownVesselPathTracker != null) {
            ownVesselPathTracker.remove();
            ownVesselPathTracker = null;
        }
    }
    
    @Override
    public void updateOwnVesselMarker(Vessel vessel) {
        if (vessel == null) {
            return;
        }
        
        // Проверяем валидность координат
        if (Double.isNaN(vessel.getLatitude()) || Double.isNaN(vessel.getLongitude()) ||
            Double.isInfinite(vessel.getLatitude()) || Double.isInfinite(vessel.getLongitude())) {
            return;
        }
        
        // ВСЕГДА пересоздаем маркер для предотвращения финализации
        if (ownVesselMarker != null) {
            ownVesselMarker.remove();
        }
        
        // Создаем новый маркер
        ownVesselMarker = new YandexMarkerWrapper(context, mapObjects, mapView, vessel, "own_vessel", settingsManager);
        if (markerClickListener != null) {
            ownVesselMarker.setClickListener(() -> {
                if (markerClickListener != null) {
                    markerClickListener.onOwnVesselClick(vessel);
                }
            });
        }
        
        // Обновляем трекер пути для собственного судна
        updateOwnVesselPath(vessel);
    }
    
    @Override
    public void updateAISVesselMarker(AISVessel vessel) {
        if (vessel == null || vessel.getMmsi() == null) {
            return;
        }
        
        // Проверяем валидность координат
        if (Double.isNaN(vessel.getLatitude()) || Double.isNaN(vessel.getLongitude()) ||
            Double.isInfinite(vessel.getLatitude()) || Double.isInfinite(vessel.getLongitude())) {
            return;
        }
        
        String mmsi = vessel.getMmsi();
        YandexMarkerWrapper marker = markerCache.get(mmsi);
        
        // ВСЕГДА пересоздаем маркер для предотвращения финализации
        if (marker != null) {
            marker.remove();
        }
        
        // Создаем новый маркер
        marker = new YandexMarkerWrapper(context, mapObjects, mapView, vessel, mmsi, settingsManager);
        markerCache.put(mmsi, marker);
        
        if (markerClickListener != null) {
            marker.setClickListener(() -> {
                if (markerClickListener != null) {
                    markerClickListener.onAISVesselClick(vessel);
                }
            });
        }
        
        // Обновляем трекер пути для AIS судна
        updateAISVesselPath(vessel);
    }
    
    @Override
    public void removeAISVesselMarker(String mmsi) {
        YandexMarkerWrapper marker = markerCache.remove(mmsi);
        if (marker != null) {
            marker.remove();
        }
        
        // Удаляем трекер пути
        VesselPathTracker pathTracker = pathTrackers.remove(mmsi);
        if (pathTracker != null) {
            pathTracker.remove();
        }
    }
    
    @Override
    public void clearAISVesselMarkers() {
        for (YandexMarkerWrapper marker : markerCache.values()) {
            marker.remove();
        }
        markerCache.clear();
        
        // Очищаем все трекеры путей AIS судов
        for (VesselPathTracker tracker : pathTrackers.values()) {
            tracker.remove();
        }
        pathTrackers.clear();
    }
    
    @Override
    public void setMarkerClickListener(MapInterface.MarkerClickListener listener) {
        this.markerClickListener = listener;
        
        // Устанавливаем обработчики для существующих маркеров
        if (ownVesselMarker != null && ownVesselMarker.isValid()) {
            ownVesselMarker.setClickListener(() -> {
                if (markerClickListener != null && ownVesselMarker.getVessel() != null) {
                    markerClickListener.onOwnVesselClick(ownVesselMarker.getVessel());
                }
            });
        }
        
        for (YandexMarkerWrapper marker : markerCache.values()) {
            if (marker.isValid()) {
                marker.setClickListener(() -> {
                    if (markerClickListener != null && marker.getAISVessel() != null) {
                        markerClickListener.onAISVesselClick(marker.getAISVessel());
                    }
                });
            }
        }
    }
    
    @Override
    public void refreshAllMarkers() {
        // При повороте карты пересоздаем все маркеры
        // Это гарантирует правильную ориентацию относительно севера
        if (mapObjects == null || mapView == null) {
            return;
        }
        
        // Пересоздаем маркер нашего судна
        if (ownVesselMarker != null) {
            Vessel vessel = ownVesselMarker.getVessel();
            if (vessel != null) {
                ownVesselMarker.remove();
                updateOwnVesselMarker(vessel);
            }
        }
        
        // Пересоздаем все AIS маркеры
        Map<String, AISVessel> vesselsToRecreate = new HashMap<>();
        for (Map.Entry<String, YandexMarkerWrapper> entry : markerCache.entrySet()) {
            YandexMarkerWrapper marker = entry.getValue();
            AISVessel vessel = marker.getAISVessel();
            if (vessel != null) {
                try {
                    marker.remove();
                } catch (RuntimeException ignored) {
                    // Игнорируем, если underlying объект недоступен
                }
                vesselsToRecreate.put(entry.getKey(), vessel);
            }
        }
        
        // Очищаем кеш и пересоздаем маркеры
        markerCache.clear();
        for (Map.Entry<String, AISVessel> entry : vesselsToRecreate.entrySet()) {
            try {
                updateAISVesselMarker(entry.getValue());
            } catch (RuntimeException ignored) {
                // Пропускаем пересоздание при ошибке
            }
        }
    }
    
    @Override
    public void checkAndRestoreMarkers() {
        // Проверяем маркер нашего судна
        if (ownVesselMarker != null && !ownVesselMarker.isValid()) {
            Vessel vessel = ownVesselMarker.getVessel();
            if (vessel != null) {
                ownVesselMarker.remove();
                updateOwnVesselMarker(vessel);
            }
        }
        
        // Проверяем AIS маркеры
        Set<String> toRemove = new HashSet<>();
        for (Map.Entry<String, YandexMarkerWrapper> entry : markerCache.entrySet()) {
            YandexMarkerWrapper marker = entry.getValue();
            if (!marker.isValid()) {
                AISVessel vessel = marker.getAISVessel();
                if (vessel != null) {
                    marker.remove();
                    toRemove.add(entry.getKey());
                    updateAISVesselMarker(vessel);
                } else {
                    toRemove.add(entry.getKey());
                }
            }
        }
        
        // Удаляем невалидные маркеры
        for (String mmsi : toRemove) {
            markerCache.remove(mmsi);
        }
    }
    
    @Override
    public int getActiveMarkerCount() {
        int count = 0;
        if (ownVesselMarker != null && ownVesselMarker.isValid()) {
            count++;
        }
        for (YandexMarkerWrapper marker : markerCache.values()) {
            if (marker.isValid()) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * Запускает периодическую очистку устаревших маркеров
     */
    private void startPeriodicCleanup() {
        cleanupRunnable = new Runnable() {
            @Override
            public void run() {
                cleanupExpiredMarkers();
                cleanupHandler.postDelayed(this, CLEANUP_INTERVAL);
            }
        };
        cleanupHandler.post(cleanupRunnable);
    }
    
    /**
     * Останавливает периодическую очистку
     */
    private void stopPeriodicCleanup() {
        if (cleanupRunnable != null) {
            cleanupHandler.removeCallbacks(cleanupRunnable);
            cleanupRunnable = null;
        }
    }
    
    /**
     * Запускает периодическое обновление маркеров
     */
    private void startPeriodicRefresh() {
        refreshRunnable = new Runnable() {
            @Override
            public void run() {
                refreshAllMarkers();
                try {
                    // Проверяем только валидность маркеров, не пересоздаем их
                    checkAndRestoreMarkers();
                } catch (Exception e) {
                    android.util.Log.e(TAG, "Ошибка при периодическом обновлении маркеров: " + e.getMessage(), e);
                }
                // Планируем следующее обновление
                refreshHandler.postDelayed(this, REFRESH_INTERVAL);
            }
        };
        refreshHandler.post(refreshRunnable);
    }
    
    /**
     * Останавливает периодическое обновление
     */
    private void stopPeriodicRefresh() {
        if (refreshRunnable != null) {
            refreshHandler.removeCallbacks(refreshRunnable);
            refreshRunnable = null;
        }
    }
    
    /**
     * Очищает устаревшие маркеры
     */
    private void cleanupExpiredMarkers() {
        // Очищаем AIS маркеры
        Set<String> toRemove = new HashSet<>();
        for (Map.Entry<String, YandexMarkerWrapper> entry : markerCache.entrySet()) {
            YandexMarkerWrapper marker = entry.getValue();
            if (marker.isExpired() || !marker.isValid() || marker.shouldBeRemoved()) {
                marker.remove();
                toRemove.add(entry.getKey());
            }
        }
        
        // Удаляем маркеры и их трекеры путей
        for (String mmsi : toRemove) {
            markerCache.remove(mmsi);
            
            // Удаляем трекер пути для этого судна
            VesselPathTracker pathTracker = pathTrackers.remove(mmsi);
            if (pathTracker != null) {
                pathTracker.remove();
            }
        }
        
        // Проверяем маркер нашего судна
        if (ownVesselMarker != null && (ownVesselMarker.isExpired() || !ownVesselMarker.isValid())) {
            ownVesselMarker.remove();
            ownVesselMarker = null;
            
            // Удаляем трекер пути нашего судна
            if (ownVesselPathTracker != null) {
                ownVesselPathTracker.remove();
                ownVesselPathTracker = null;
            }
        }
    }
    
    /**
     * Принудительно обновляет все маркеры (например, при изменении зума)
     */
    public void forceRefreshAllMarkers() {
        // Пересоздаем маркер нашего судна
        if (ownVesselMarker != null) {
            Vessel vessel = ownVesselMarker.getVessel();
            if (vessel != null) {
                ownVesselMarker.remove();
                updateOwnVesselMarker(vessel);
            }
        }
        
        // Пересоздаем все AIS маркеры
        Map<String, AISVessel> vesselsToRecreate = new HashMap<>();
        for (Map.Entry<String, YandexMarkerWrapper> entry : markerCache.entrySet()) {
            YandexMarkerWrapper marker = entry.getValue();
            AISVessel vessel = marker.getAISVessel();
            if (vessel != null) {
                marker.remove();
                vesselsToRecreate.put(entry.getKey(), vessel);
            }
        }
        
        // Очищаем кеш и трекеры путей
        markerCache.clear();
        
        // Очищаем все трекеры путей AIS судов
        for (VesselPathTracker tracker : pathTrackers.values()) {
            tracker.remove();
        }
        pathTrackers.clear();
        
        // Пересоздаем маркеры
        for (Map.Entry<String, AISVessel> entry : vesselsToRecreate.entrySet()) {
            updateAISVesselMarker(entry.getValue());
        }
    }
    
    @Override
    public void setPathTrackingEnabled(boolean enabled) {
        this.pathTrackingEnabled = enabled;
        
        // Сохраняем настройку в SettingsManager
        if (settingsManager != null) {
            settingsManager.setPathTrackingEnabled(enabled);
        }
        
        // Обновляем состояние всех трекеров
        if (ownVesselPathTracker != null) {
            ownVesselPathTracker.setEnabled(enabled);
        }
        
        for (VesselPathTracker tracker : pathTrackers.values()) {
            tracker.setEnabled(enabled);
        }
    }
    
    @Override
    public void clearVesselPath(String mmsi) {
        VesselPathTracker tracker = pathTrackers.get(mmsi);
        if (tracker != null) {
            tracker.clearPath();
        }
    }
    
    @Override
    public void clearAllPaths() {
        if (ownVesselPathTracker != null) {
            ownVesselPathTracker.clearPath();
        }
        
        for (VesselPathTracker tracker : pathTrackers.values()) {
            tracker.clearPath();
        }
    }
    
    @Override
    public void updatePathSettings(int pathColor, int predictionColor, float pathWidth, float predictionWidth) {
        // Сохраняем настройки в SettingsManager
        if (settingsManager != null) {
            settingsManager.setPathColor(pathColor);
            settingsManager.setPredictionColor(predictionColor);
            settingsManager.setPathWidth(pathWidth);
            settingsManager.setPredictionWidth(predictionWidth);
        }
        
        // Обновляем настройки всех трекеров
        if (ownVesselPathTracker != null) {
            ownVesselPathTracker.setPathColor(pathColor);
            ownVesselPathTracker.setPredictionColor(predictionColor);
            ownVesselPathTracker.setLineWidth(pathWidth, predictionWidth);
        }
        
        for (VesselPathTracker tracker : pathTrackers.values()) {
            tracker.setPathColor(pathColor);
            tracker.setPredictionColor(predictionColor);
            tracker.setLineWidth(pathWidth, predictionWidth);
        }
    }
    
    /**
     * Обновляет трекер пути для собственного судна
     */
    private void updateOwnVesselPath(Vessel vessel) {
        if (!pathTrackingEnabled || vessel == null) {
            return;
        }
        
        // Проверяем, движется ли судно
        if (!isVesselMoving(vessel)) {
            return;
        }
        
        if (ownVesselPathTracker == null) {
            ownVesselPathTracker = new VesselPathTracker("own_vessel", mapObjects);
        }
        
        ownVesselPathTracker.updatePosition(
            vessel.getLatitude(),
            vessel.getLongitude(),
            vessel.getSpeed(),
            vessel.getCourse()
        );
    }
    
    /**
     * Обновляет трекер пути для AIS судна
     */
    private void updateAISVesselPath(AISVessel vessel) {
        if (!pathTrackingEnabled || vessel == null || vessel.getMmsi() == null) {
            return;
        }
        
        // Проверяем, движется ли судно
        if (!isAISVesselMoving(vessel)) {
            return;
        }
        
        String mmsi = vessel.getMmsi();
        VesselPathTracker tracker = pathTrackers.get(mmsi);
        
        if (tracker == null) {
            tracker = new VesselPathTracker(mmsi, mapObjects);
            pathTrackers.put(mmsi, tracker);
        }
        
        // Курс для прогноза: HDG (0..359) если валиден, иначе COG
        double displayCourse = getAISDisplayCourse(vessel);
        
        tracker.updatePosition(
            vessel.getLatitude(),
            vessel.getLongitude(),
            vessel.getSpeed(),
            displayCourse
        );
    }
    
    /**
     * Проверяет, движется ли собственное судно
     */
    private boolean isVesselMoving(Vessel vessel) {
        if (vessel == null) {
            return false;
        }
        
        // Считаем, что судно движется, если скорость больше 0.5 узла
        return vessel.getSpeed() > 0.5;
    }
    
    /**
     * Проверяет, движется ли AIS судно
     */
    private boolean isAISVesselMoving(AISVessel vessel) {
        if (vessel == null) {
            return false;
        }
        
        // Проверяем навигационный статус
        String navStatus = vessel.getNavigationalStatus();
        if (navStatus != null) {
            String status = navStatus.toLowerCase();
            // Считаем, что судно движется, если не стоит на якоре и не пришвартовано
            if (status.contains("at anchor") || 
                status.contains("moored") || 
                status.contains("not under command")) {
                return false;
            }
        }
        
        // Считаем, что судно движется, если скорость больше 0.5 узла
        return vessel.getSpeed() > 0.5;
    }

    /**
     * Возвращает курс для AIS: валидный HDG (0..359), 511 — невалидно; иначе COG
     */
    private double getAISDisplayCourse(AISVessel vessel) {
        try {
            double hdg = vessel.getHeading();
            if (isValidHeading(hdg)) {
                return normalizeCourse(hdg);
            }
            return normalizeCourse(vessel.getCourse());
        } catch (Exception ignored) {
            return 0.0;
        }
    }

    /**
     * Проверяет валидность HDG
     */
    private boolean isValidHeading(double heading) {
        if (Double.isNaN(heading) || Double.isInfinite(heading)) return false;
        int h = (int) Math.round(heading);
        if (h == 511) return false;
        return h >= 0 && h <= 359;
    }

    /**
     * Нормализует курс в диапазон [0, 360)
     */
    private double normalizeCourse(double course) {
        if (Double.isNaN(course) || Double.isInfinite(course)) return 0.0;
        double c = course % 360.0;
        if (c < 0) c += 360.0;
        return c;
    }
}
