package com.grigowashere.aismap.ui;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.grigowashere.aismap.maps.MapInterface;
import com.grigowashere.aismap.maps.MapInterfaceChangeListener;
import com.grigowashere.aismap.models.Vessel;
import com.grigowashere.aismap.models.AISVessel;

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

/**
 * Координатор UI отрисовки
 * Единая точка всех операций с картой и UI
 * Обеспечивает throttling и батчинг операций
 * Подписывается на изменения MapInterface для автоматического обновления
 */
public class UIRenderingCoordinator implements UIDataChangeNotifier, MapInterfaceChangeListener {
    private static final String TAG = "UIRenderingCoordinator";
    
    // Throttling интервалы
    public static final long VESSEL_UPDATE_THROTTLE = 500;     // 500мс для позиции судна
    public static final long AIS_UPDATE_THROTTLE = 1000;     // 1сек для AIS данных
    public static final long PATH_UPDATE_THROTTLE = 2000;    // 2сек для путей
    
    private MapInterface mapInterface;
    private Handler uiHandler;
    
    // Pending операции для батчинга
    private Vessel pendingVesselUpdate;
    private final Map<String, AISVessel> pendingAISUpdates = new HashMap<>();
    private final Set<String> pendingAISRemovals = new HashSet<>();
    
    // Throttling Runnable's
    private Runnable vesselUpdateRunnable;
    private Runnable aisUpdateRunnable;
    private Runnable pathUpdateRunnable;
    
    // Флаги для предотвращения множественных запланированных операций
    private boolean vesselUpdatePending = false;
    private boolean aisUpdatePending = false;
    private boolean pathUpdatePending = false;
    
    public UIRenderingCoordinator(MapInterface mapInterface) {
        this.mapInterface = mapInterface;
        this.uiHandler = new Handler(Looper.getMainLooper());
        
        setupThrottling();
        Log.i(TAG, "UIRenderingCoordinator инициализирован");
    }
    
    /**
     * Настройка throttling механизмов
     */
    private void setupThrottling() {
        vesselUpdateRunnable = () -> {
            vesselUpdatePending = false;
            executeVesselUpdate();
        };
        
        aisUpdateRunnable = () -> {
            aisUpdatePending = false;
            executeAISUpdates();
        };
        
        pathUpdateRunnable = () -> {
            pathUpdatePending = false;
            executePathUpdates();
        };
    }
    
    /**
     * Запрос обновления позиции собственного судна
     */
    public void requestVesselUpdate(Vessel vessel) {
        if (vessel == null) return;
        
        pendingVesselUpdate = vessel;
        
        if (!vesselUpdatePending) {
            vesselUpdatePending = true;
            uiHandler.removeCallbacks(vesselUpdateRunnable);
            uiHandler.postDelayed(vesselUpdateRunnable, VESSEL_UPDATE_THROTTLE);
            
            Log.d(TAG, "Vessel update запланирован на " + VESSEL_UPDATE_THROTTLE + "мс");
        }
    }
    
    /**
     * Запрос обновления AIS судна
     */
    public void requestAISUpdate(AISVessel vessel) {
        if (vessel == null || vessel.getMmsi() == null) return;
        
        pendingAISUpdates.put(vessel.getMmsi(), vessel);
        
        if (!aisUpdatePending) {
            aisUpdatePending = true;
            uiHandler.removeCallbacks(aisUpdateRunnable);
            uiHandler.postDelayed(aisUpdateRunnable, AIS_UPDATE_THROTTLE);
            
            Log.d(TAG, "AIS update запланирован на " + AIS_UPDATE_THROTTLE + "мс");
        }
    }
    
    /**
     * Запрос удаления AIS судна
     */
    public void requestAISRemoval(String mmsi) {
        if (mmsi == null) return;
        
        pendingAISRemovals.add(mmsi);
        pendingAISUpdates.remove(mmsi); // Убираем из обновлений
        
        if (!aisUpdatePending) {
            aisUpdatePending = true;
            uiHandler.removeCallbacks(aisUpdateRunnable);
            uiHandler.postDelayed(aisUpdateRunnable, AIS_UPDATE_THROTTLE);
            
            Log.d(TAG, "AIS removal запланирован на " + AIS_UPDATE_THROTTLE + "мс");
        }
    }
    
    /**
     * Выполнение обновления позиции судна
     */
    private void executeVesselUpdate() {
        if (mapInterface == null || pendingVesselUpdate == null) return;
        
        try {
            Log.d(TAG, "Выполняем vessel update: " + pendingVesselUpdate.getLatitude() + "," + pendingVesselUpdate.getLongitude());
            mapInterface.updateOwnVesselPosition(pendingVesselUpdate);
            Log.d(TAG, "Vessel update выполнен успешно");
        } catch (Exception e) {
            Log.e(TAG, "Ошибка vessel update: " + e.getMessage(), e);
        }
        
        pendingVesselUpdate = null;
    }
    
    /**
     * Выполнение обновлений AIS судов
     */
    private void executeAISUpdates() {
        if (mapInterface == null) return;
        
        try {
            // Удаляем старые суда
            for (String mmsi : pendingAISRemovals) {
                Log.d(TAG, "Удаляем AIS судно: " + mmsi);
                mapInterface.removeAISVesselMarker(mmsi);
            }
            
            // Обновляем или добавляем суда пачкой, чтобы карта сделала один GeoJSON refresh.
            List<AISVessel> updates = new ArrayList<>(pendingAISUpdates.values());
            if (!updates.isEmpty()) {
                mapInterface.updateAISVesselPositions(updates);
            }
            
            Log.d(TAG, "AIS updates выполнены: удалено=" + pendingAISRemovals.size() + 
                        ", обновлено=" + pendingAISUpdates.size());
        } catch (Exception e) {
            Log.e(TAG, "Ошибка AIS updates: " + e.getMessage(), e);
        }
        
        // Очищаем pending операции
        pendingAISUpdates.clear();
        pendingAISRemovals.clear();
    }
    
    /**
     * Выполнение обновлений путей (заглушка для будущего)
     */
    private void executePathUpdates() {
        if (mapInterface == null) return;
        
        try {
            // Обновляем пути на карте
            // MapInterface должен обновить все пути AIS судов
            mapInterface.updateAllVesselPaths();
            Log.d(TAG, "Path updates выполнены");
        } catch (Exception e) {
            Log.e(TAG, "Ошибка path updates: " + e.getMessage(), e);
        }
    }
    
    /**
     * Принудительное выполнение всех pending операций
     */
    public void flushPendingOperations() {
        Log.i(TAG, "Принудительное выполнение всех pending операций");
        
        if (uiHandler != null) {
            uiHandler.removeCallbacks(vesselUpdateRunnable);
            uiHandler.removeCallbacks(aisUpdateRunnable);
            uiHandler.removeCallbacks(pathUpdateRunnable);
        }
        
        vesselUpdatePending = false;
        aisUpdatePending = false;
        pathUpdatePending = false;
        
        executeVesselUpdate();
        executeAISUpdates();
        executePathUpdates();
        
        Log.i(TAG, "Все pending операции выполнены");
    }
    
    /**
     * Очистка ресурсов
     */
    public void cleanup() {
        Log.i(TAG, "Очистка UIRenderingCoordinator");
        
        if (uiHandler != null) {
            uiHandler.removeCallbacksAndMessages(null);
        }
        
        flushPendingOperations();
        mapInterface = null;
        
        Log.i(TAG, "UIRenderingCoordinator очищен");
    }
    
    // ========== Реализация UIDataChangeNotifier ==========
    
    @Override
    public void onVesselPositionChanged(Vessel vessel) {
        requestVesselUpdate(vessel);
    }
    
    @Override
    public void onGPSQualityChanged(Vessel vessel) {
        // GPS качество влияет на отображение точности, но не требует urgent update
        requestVesselUpdate(vessel);
    }
    
    @Override
    public void onAISVesselChanged(AISVessel vessel) {
        requestAISUpdate(vessel);
    }
    
    @Override
    public void onAISVesselRemoved(String mmsi) {
        requestAISRemoval(mmsi);
    }
    
    @Override
    public void onVesselPathChanged(String mmsi) {
        // Path изменения менее критичны, используем больше throttling
        if (!pathUpdatePending) {
            pathUpdatePending = true;
            uiHandler.removeCallbacks(pathUpdateRunnable);
            uiHandler.postDelayed(pathUpdateRunnable, PATH_UPDATE_THROTTLE);
            
            Log.d(TAG, "Path update запланирован на " + PATH_UPDATE_THROTTLE + "мс");
        }
    }
    
    @Override
    public void onRequestCenterMap(double latitude, double longitude) {
        // Центрирование карты должно происходить немедленно
        uiHandler.post(() -> {
            if (mapInterface != null) {
                mapInterface.centerOnPosition(latitude, longitude);
                Log.d(TAG, "Карта отцентрирована на " + latitude + "," + longitude);
            }
        });
    }
    
    @Override
    public void onCompassUpdate(float azimuth) {
        // Компас не относится к карте, передаем в MainActivity через callback
        Log.d(TAG, "Compass update: " + azimuth + "° - требует специальной обработки в MainActivity");
    }
    
    /**
     * Реализация MapInterfaceChangeListener
     * Вызывается при смене MapInterface в MapController
     */
    @Override
    public void onMapInterfaceChanged(MapInterface oldMapInterface, MapInterface newMapInterface) {
        Log.i(TAG, "🔄 MapInterface изменен в UIRenderingCoordinator");
        Log.i(TAG, "  Старый: " + (oldMapInterface != null ? oldMapInterface.getClass().getSimpleName() : "null"));
        Log.i(TAG, "  Новый: " + (newMapInterface != null ? newMapInterface.getClass().getSimpleName() : "null"));
        
        // Обновляем ссылку на MapInterface
        this.mapInterface = newMapInterface;
        
        if (newMapInterface != null) {
            Log.i(TAG, "✅ UIRenderingCoordinator обновлен с новым MapInterface");
            
            // Переносим pending операции на новую карту
            transferPendingOperationsToNewMap();
        } else {
            Log.w(TAG, "⚠️ Новый MapInterface равен null - очищаем pending операции");
            clearPendingOperations();
        }
    }
    
    /**
     * Переносит pending операции на новую карту
     */
    private void transferPendingOperationsToNewMap() {
        if (mapInterface == null) {
            Log.w(TAG, "⚠️ MapInterface равен null, нельзя перенести операции");
            return;
        }
        
        Log.i(TAG, "🔄 Перенос pending операций на новую карту");
        
        // Выполняем pending операции немедленно на новой карте
        uiHandler.post(() -> {
            try {
                // Выполняем pending vessel update
                if (pendingVesselUpdate != null) {
                    Log.d(TAG, "📍 Выполняем pending vessel update");
                    executeVesselUpdate();
                }
                
                // Выполняем pending AIS updates
                if (!pendingAISUpdates.isEmpty()) {
                    Log.d(TAG, "🚢 Выполняем " + pendingAISUpdates.size() + " pending AIS updates");
                    executeAISUpdates();
                }
                
                // Выполняем pending AIS removals
                if (!pendingAISRemovals.isEmpty()) {
                    Log.d(TAG, "🗑️ Выполняем " + pendingAISRemovals.size() + " pending AIS removals");
                    executeAISUpdates(); // Этот метод обрабатывает и удаления тоже
                }
                
                Log.i(TAG, "✅ Pending операции перенесены на новую карту");
                
            } catch (Exception e) {
                Log.e(TAG, "❌ Ошибка при переносе pending операций: " + e.getMessage(), e);
            }
        });
    }
    
    /**
     * Очищает все pending операции
     */
    private void clearPendingOperations() {
        Log.i(TAG, "🧹 Очистка всех pending операций");
        
        pendingVesselUpdate = null;
        pendingAISUpdates.clear();
        pendingAISRemovals.clear();
        
        // Сбрасываем флаги
        vesselUpdatePending = false;
        aisUpdatePending = false;
        pathUpdatePending = false;
        
        // Отменяем все запланированные операции
        uiHandler.removeCallbacks(vesselUpdateRunnable);
        uiHandler.removeCallbacks(aisUpdateRunnable);
        uiHandler.removeCallbacks(pathUpdateRunnable);
        
        Log.i(TAG, "✅ Pending операции очищены");
    }
}
