package com.grigowashere.aismap.controllers;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.grigowashere.aismap.data.Repository;
import com.grigowashere.aismap.data.entity.VesselEntity;
import com.grigowashere.aismap.data.entity.AISVesselEntity;
import com.grigowashere.aismap.data.mapper.AISVesselMapper;
import com.grigowashere.aismap.models.Vessel;
import com.grigowashere.aismap.models.AISVessel;
import com.grigowashere.aismap.models.AISNavigationAid;
import com.grigowashere.aismap.utils.SettingsManager;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Контроллер для операций с базой данных
 * Отвечает только за сохранение, загрузку и очистку данных
 */
public class DataController {
    
    private static final String TAG = "DataController";
    
    private Context context;
    private Repository repository;
    private SettingsManager settingsManager;
    private ExecutorService executor;
    
    // Периодическая очистка БД от устаревших AIS целей
    private Handler dbCleanupHandler;
    private Runnable dbCleanupRunnable;
    private static final long DB_CLEANUP_INTERVAL = 60000; // 1 минута
    
    // Callbacks для уведомления других компонентов
    private DataControllerListener listener;
    
    public interface DataControllerListener {
        void onDataRestored(Vessel vessel, List<AISVessel> aisVessels, List<AISNavigationAid> navigationAids);
        void onDataSaved(String dataType, boolean success);
        void onDataCleaned(int removedCount);
    }
    
    public DataController(Context context) {
        this.context = context;
        this.repository = new Repository(context);
        this.settingsManager = new SettingsManager(context);
        this.executor = Executors.newSingleThreadExecutor();
        
        // Инициализируем Handler для периодической очистки БД
        this.dbCleanupHandler = new Handler(Looper.getMainLooper());
        this.dbCleanupRunnable = this::performDatabaseCleanup;
        
        Log.i(TAG, "Data Controller инициализирован");
    }
    
    /**
     * Устанавливает слушателя для уведомлений
     */
    public void setListener(DataControllerListener listener) {
        this.listener = listener;
    }
    
    /**
     * Восстанавливает данные из БД асинхронно
     */
    public void restoreDataAsync() {
        Log.i(TAG, "🔄 Запускаем асинхронное восстановление данных из БД...");
        executor.execute(() -> {
            try {
                cleanupStaleAISSync("перед восстановлением");

                Log.d(TAG, "📊 Загружаем данные судна из БД...");
                VesselEntity latest = repository.getLatestOwnVesselSync();
                Vessel vessel = null;
                if (latest != null) {
                    vessel = new Vessel();
                    vessel.setLatitude(latest.latitude);
                    vessel.setLongitude(latest.longitude);
                    vessel.setAccuracy(latest.accuracy);
                    vessel.setFixTime(latest.fixTime);
                    Log.d(TAG, "✅ Данные судна восстановлены: " + latest.latitude + "," + latest.longitude);
                } else {
                    Log.d(TAG, "ℹ️ Нет данных судна в БД");
                }
                
                Log.d(TAG, "🚢 Загружаем AIS суда из БД...");
                List<AISVesselEntity> list = repository.getAllAISSync();
                List<AISVessel> aisVessels = new ArrayList<>();
                List<AISNavigationAid> navigationAids = new ArrayList<>();
                
                if (list != null && !list.isEmpty()) {
                    for (AISVesselEntity entity : list) {
                        // Проверяем, является ли это навигационным знаком
                        if ("Navigation Aid".equals(entity.vesselClass)) {
                            // Создаем AISNavigationAid из entity
                            AISNavigationAid navigationAid = createNavigationAidFromEntity(entity);
                            navigationAids.add(navigationAid);
                        } else {
                            // Используем маппер для полного восстановления всех полей AIS судна
                            AISVessel vesselModel = AISVesselMapper.toModel(entity);
                            aisVessels.add(vesselModel);
                        }
                    }
                    Log.i(TAG, "✅ Восстановлено " + aisVessels.size() + " AIS судов и " + navigationAids.size() + " навигационных знаков из БД");
                } else {
                    Log.d(TAG, "ℹ️ Нет AIS судов в БД");
                }
                
                // Уведомляем слушателя о восстановленных данных
                if (listener != null) {
                    listener.onDataRestored(vessel, aisVessels, navigationAids);
                }
                
            } catch (Exception e) {
                Log.e(TAG, "❌ Ошибка восстановления данных из БД: " + e.getMessage(), e);
            }
        });
    }
    
    /**
     * Сохраняет позицию судна в БД
     */
    public void saveVesselPosition(Vessel vessel) {
        if (vessel == null) return;
        
        executor.execute(() -> {
            try {
                VesselEntity ve = new VesselEntity();
                ve.latitude = vessel.getLatitude();
                ve.longitude = vessel.getLongitude();
                ve.accuracy = vessel.getAccuracy();
                ve.fixTime = vessel.getFixTime();
                repository.upsertOwnVessel(ve);
                
                if (listener != null) {
                    listener.onDataSaved("vessel_position", true);
                }
            } catch (Exception e) {
                Log.e(TAG, "Ошибка сохранения позиции в БД: " + e.getMessage(), e);
                if (listener != null) {
                    listener.onDataSaved("vessel_position", false);
                }
            }
        });
    }
    
    /**
     * Сохраняет AIS судно в БД
     */
    public void saveAISVessel(AISVessel vessel) {
        if (vessel == null) return;
        
        executor.execute(() -> {
            try {
                // Используем маппер для полной конвертации всех полей
                AISVesselEntity entity = AISVesselMapper.toEntity(vessel);
                repository.upsertAISSync(entity);
                Log.d(TAG, "AIS судно сохранено в БД: " + vessel.getMmsi());
                
                if (listener != null) {
                    listener.onDataSaved("ais_vessel", true);
                }
            } catch (Exception e) {
                Log.e(TAG, "Ошибка апсерта AIS в БД: " + e.getMessage(), e);
                if (listener != null) {
                    listener.onDataSaved("ais_vessel", false);
                }
            }
        });
    }

    /**
     * Пакетно сохраняет AIS суда в БД.
     */
    public void saveAISVessels(List<AISVessel> vessels) {
        if (vessels == null || vessels.isEmpty()) return;

        executor.execute(() -> {
            try {
                List<AISVesselEntity> entities = new ArrayList<>(vessels.size());
                for (AISVessel vessel : vessels) {
                    if (vessel == null || vessel.getMmsi() == null) continue;
                    AISVesselEntity entity = AISVesselMapper.toEntity(vessel);
                    if (entity != null) {
                        entities.add(entity);
                    }
                }
                repository.upsertAISBatchSync(entities);
                Log.d(TAG, "Пакетно сохранено AIS судов в БД: " + entities.size());

                if (listener != null) {
                    listener.onDataSaved("ais_vessels_batch", true);
                }
            } catch (Exception e) {
                Log.e(TAG, "Ошибка пакетного апсерта AIS в БД: " + e.getMessage(), e);
                if (listener != null) {
                    listener.onDataSaved("ais_vessels_batch", false);
                }
            }
        });
    }

    /**
     * Сохраняет навигационный знак в БД
     */
    public void saveNavigationAid(AISNavigationAid navigationAid) {
        if (navigationAid == null) return;
        
        executor.execute(() -> {
            try {
                // Создаем AISVesselEntity из навигационного знака для совместимости с БД
                AISVesselEntity entity = new AISVesselEntity(navigationAid.getMmsi());
                entity.mmsi = navigationAid.getMmsi();
                entity.latitude = navigationAid.getLatitude();
                entity.longitude = navigationAid.getLongitude();
                entity.vesselName = navigationAid.getAidName();
                entity.vesselClass = "Navigation Aid";
                entity.vesselType = navigationAid.getAidTypeDescription();
                entity.length = navigationAid.getLength();
                entity.width = navigationAid.getWidth();
                entity.draft = navigationAid.getDraft();
                entity.positionAccuracy = navigationAid.isPositionAccuracy();
                // Сохраняем время последнего обновления как epoch ms
                if (navigationAid.getLastUpdate() != null) {
                    entity.lastUpdateEpochMs = navigationAid.getLastUpdate().atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli();
                }
                
                // Добавляем специальные поля для навигационных знаков в destination
                StringBuilder destination = new StringBuilder();
                destination.append("Type: ").append(navigationAid.getAidType()).append(" (").append(navigationAid.getAidTypeDescription()).append(")");
                if (navigationAid.isOffPositionIndicator()) {
                    destination.append(" - Off Position");
                }
                if (navigationAid.isRaimFlag()) {
                    destination.append(" - RAIM Active");
                }
                entity.destination = destination.toString();
                
                repository.upsertAISSync(entity);
                Log.d(TAG, "Навигационный знак сохранен в БД: " + navigationAid.getMmsi());
                
                if (listener != null) {
                    listener.onDataSaved("navigation_aid", true);
                }
            } catch (Exception e) {
                Log.e(TAG, "Ошибка сохранения навигационного знака в БД: " + e.getMessage(), e);
                if (listener != null) {
                    listener.onDataSaved("navigation_aid", false);
                }
            }
        });
    }

    /**
     * Создает AISNavigationAid из AISVesselEntity
     */
    private AISNavigationAid createNavigationAidFromEntity(AISVesselEntity entity) {
        AISNavigationAid navigationAid = new AISNavigationAid(entity.mmsi);
        navigationAid.setLatitude(entity.latitude);
        navigationAid.setLongitude(entity.longitude);
        navigationAid.setAidName(entity.vesselName);
        navigationAid.setAidTypeDescription(entity.vesselType);
        navigationAid.setLength(entity.length);
        navigationAid.setWidth(entity.width);
        navigationAid.setDraft(entity.draft);
        navigationAid.setPositionAccuracy(entity.positionAccuracy);
        // Восстанавливаем время из epoch ms, если доступно
        if (entity.lastUpdateEpochMs > 0) {
            navigationAid.setLastUpdate(java.time.Instant.ofEpochMilli(entity.lastUpdateEpochMs)
                .atZone(java.time.ZoneId.systemDefault()).toLocalDateTime());
        }
        
        // Парсим специальные поля из destination
        if (entity.destination != null && entity.destination.startsWith("Type: ")) {
            try {
                // Извлекаем тип из destination: "Type: 21 (Cardinal Mark E)"
                String typePart = entity.destination.substring(6); // Убираем "Type: "
                int parenIndex = typePart.indexOf(' ');
                if (parenIndex > 0) {
                    String typeStr = typePart.substring(0, parenIndex);
                    int aidType = Integer.parseInt(typeStr);
                    navigationAid.setAidType(aidType);
                }
                
                // Проверяем дополнительные флаги
                if (entity.destination.contains("Off Position")) {
                    navigationAid.setOffPositionIndicator(true);
                }
                if (entity.destination.contains("RAIM Active")) {
                    navigationAid.setRaimFlag(true);
                }
            } catch (Exception e) {
                Log.w(TAG, "Ошибка парсинга destination для навигационного знака: " + entity.destination);
            }
        }
        
        return navigationAid;
    }
    
    /**
     * Запускает периодическую очистку БД от устаревших 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() {
        executor.execute(() -> {
            try {
                int removed = cleanupStaleAISSync(null);

                if (listener != null) {
                    listener.onDataCleaned(removed);
                }

                // Планируем следующую очистку
                if (dbCleanupHandler != null && dbCleanupRunnable != null) {
                    dbCleanupHandler.postDelayed(dbCleanupRunnable, DB_CLEANUP_INTERVAL);
                }
            } catch (Exception e) {
                Log.e(TAG, "Ошибка при очистке БД от устаревших AIS целей: " + e.getMessage(), e);
            }
        });
    }

    private int cleanupStaleAISSync(String reason) {
        int staleRemoveMinutes = settingsManager.getDataStaleRemoveMinutes();
        long thresholdEpochMs = System.currentTimeMillis() - (staleRemoveMinutes * 60 * 1000L);
        int removed = repository.deleteStaleAISSync(thresholdEpochMs);
        String suffix = reason != null ? " " + reason : "";
        Log.i(TAG, "Выполнена очистка БД" + suffix + ": удалено=" + removed +
            ", старше=" + staleRemoveMinutes + " минут");
        return removed;
    }
    
    /**
     * Получает Repository для прямого доступа (если необходимо)
     */
    public Repository getRepository() {
        return repository;
    }
    
    /**
     * Получает SettingsManager для прямого доступа (если необходимо)
     */
    public SettingsManager getSettingsManager() {
        return settingsManager;
    }
    
    /**
     * Освобождает ресурсы
     */
    public void cleanup() {
        stopDatabaseCleanup();
        
        // Очищаем Handler для предотвращения утечек памяти
        if (dbCleanupHandler != null) {
            dbCleanupHandler.removeCallbacksAndMessages(null);
        }
        
        if (executor != null && !executor.isShutdown()) {
            executor.shutdown();
            try {
                // Ждем завершения всех задач максимум 2 секунды
                if (!executor.awaitTermination(2, java.util.concurrent.TimeUnit.SECONDS)) {
                    Log.w(TAG, "Thread pool did not terminate gracefully, forcing shutdown");
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                Log.w(TAG, "Thread pool shutdown interrupted: " + e.getMessage());
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        
        Log.i(TAG, "Data Controller очищен");
    }
}
