package com.grigowashere.aismap.controllers;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.grigowashere.aismap.models.VesselPathPoint;
import com.grigowashere.aismap.utils.SettingsManager;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * Контроллер для управления путем судна
 * Отвечает за запись, сохранение и восстановление точек пути
 */
public class VesselPathController {
    
    private static final String TAG = "VesselPathController";
    private static final String PREFS_NAME_PREFIX = "VesselPathData_";
    private static final String KEY_PATH_POINTS = "path_points";
    private static final String KEY_LAST_UPDATE = "last_update";
    
    // Минимальное расстояние между точками (в метрах)
    private static final double MIN_DISTANCE_METERS = 1.0; // Уменьшено с 10.0 до 1.0 метра
    
    // Минимальное время между точками (в секундах)
    private static final long MIN_TIME_SECONDS = 1; // Уменьшено с 5 до 1 секунды
    
    // Максимальное количество точек для производительности
    private static final int MAX_PATH_POINTS = 1000; // Ограничение для предотвращения зависаний
    
    private Context context;
    private SettingsManager settingsManager;
    private SharedPreferences prefs;
    private String vesselId; // Уникальный идентификатор судна
    
    // Handler для UI операций
    private Handler uiHandler;
    
    // Список точек пути
    private List<VesselPathPoint> pathPoints;
    
    // Последняя добавленная точка
    private VesselPathPoint lastPoint;
    
    public VesselPathController(Context context, SettingsManager settingsManager) {
        this(context, settingsManager, "own_vessel"); // По умолчанию для собственного судна
    }
    
    public VesselPathController(Context context, SettingsManager settingsManager, String vesselId) {
        this.context = context;
        this.settingsManager = settingsManager;
        this.vesselId = vesselId;
        this.prefs = context.getSharedPreferences(PREFS_NAME_PREFIX + vesselId, Context.MODE_PRIVATE);
        this.pathPoints = new ArrayList<>();
        this.uiHandler = new Handler(Looper.getMainLooper());
        
        // Загружаем сохраненные точки в фоновом потоке
        loadPathPointsAsync();
        
        Log.i(TAG, "VesselPathController инициализирован для судна " + vesselId);
    }
    
    /**
     * Добавляет новую точку пути
     * @param longitude долгота
     * @param latitude широта
     * @param speed скорость в узлах
     * @return true если точка была добавлена, false если пропущена
     */
    public boolean addPathPoint(double longitude, double latitude, float speed) {
        // Проверяем валидность координат
        if (!isValidCoordinates(latitude, longitude)) {
            Log.d(TAG, "addPathPoint: invalid coordinates " + latitude + "," + longitude + " - skipping");
            return false;
        }
        
        VesselPathPoint newPoint = new VesselPathPoint(longitude, latitude, speed);
        
        // Проверяем, нужно ли добавлять точку
        if (shouldAddPoint(newPoint)) {
            // Синхронизируем доступ к pathPoints для избежания гонки потоков
            synchronized (pathPoints) {
                pathPoints.add(newPoint);
                lastPoint = newPoint;
                
                // Ограничиваем количество точек
                limitPathPoints();
            }
            
            // Сохраняем изменения
            savePathPoints();
            
            Log.d(TAG, "Добавлена точка пути: " + newPoint + ", всего точек: " + pathPoints.size());
            return true;
        }
        
        return false;
    }
    
    /**
     * Проверяет, нужно ли добавлять точку
     */
    private boolean shouldAddPoint(VesselPathPoint newPoint) {
        // Если это первая точка
        if (lastPoint == null) {
            return true;
        }
        
        // Проверяем расстояние
        double distance = lastPoint.distanceTo(newPoint);
        if (distance < MIN_DISTANCE_METERS) {
            Log.d(TAG, "Точка пропущена: расстояние слишком мало (" + distance + "м)");
            return false;
        }
        
        // Проверяем время
        long timeDiff = lastPoint.timeDifferenceSeconds(newPoint);
        if (timeDiff < MIN_TIME_SECONDS) {
            Log.d(TAG, "Точка пропущена: время слишком мало (" + timeDiff + "с)");
            return false;
        }
        
        return true;
    }
    
    /**
     * Ограничивает количество точек пути
     */
    private void limitPathPoints() {
        int maxPoints = settingsManager.getPathMaxPoints();
        Log.d(TAG, "limitPathPoints: текущих точек=" + pathPoints.size() + ", лимит=" + maxPoints);
        
        if (pathPoints.size() > maxPoints) {
            // Удаляем самые старые точки
            int toRemove = pathPoints.size() - maxPoints;
            for (int i = 0; i < toRemove; i++) {
                pathPoints.remove(0);
            }
            Log.d(TAG, "Удалено " + toRemove + " старых точек пути, осталось: " + pathPoints.size());
        }
    }
    
    /**
     * Получает точки пути в формате JSONArray для MapLibre
     */
    public JSONArray getPathCoordinates() {
        JSONArray coords = new JSONArray();
        
        try {
            // Синхронизируем доступ к pathPoints для избежания гонки потоков
            synchronized (pathPoints) {
                for (VesselPathPoint point : pathPoints) {
                    JSONArray coord = new JSONArray();
                    coord.put(point.getLongitude());
                    coord.put(point.getLatitude());
                    coords.put(coord);
                }
            }
        } catch (JSONException e) {
            Log.e(TAG, "Ошибка создания координат пути", e);
        }
        
        return coords;
    }
    
    /**
     * Получает точки пути в формате JSONArray для MapLibre с учетом скорости
     * Возвращает массив координат с информацией о скорости для динамического пунктира
     */
    public JSONArray getPathCoordinatesWithSpeed() {
        JSONArray coords = new JSONArray();
        
        try {
            // Синхронизируем доступ к pathPoints для избежания гонки потоков
            synchronized (pathPoints) {
                // Убираем лишние логи
                // Log.d(TAG, "getPathCoordinatesWithSpeed: обрабатываем " + pathPoints.size() + " точек");
                for (VesselPathPoint point : pathPoints) {
                    JSONArray coord = new JSONArray();
                    coord.put(point.getLongitude());
                    coord.put(point.getLatitude());
                    coord.put(point.getSpeed()); // Добавляем скорость для динамического пунктира
                    coords.put(coord);
                }
            }
            // Убираем лишние логи
            // Log.d(TAG, "getPathCoordinatesWithSpeed: создано " + coords.length() + " координат");
        } catch (JSONException e) {
            Log.e(TAG, "Ошибка создания координат пути с скоростью", e);
        }
        
        return coords;
    }
    
    /**
     * Вычисляет среднюю скорость на участке пути
     */
    public float getAverageSpeed() {
        if (pathPoints.size() < 2) {
            return 0.0f;
        }
        
        float totalSpeed = 0.0f;
        for (VesselPathPoint point : pathPoints) {
            totalSpeed += point.getSpeed();
        }
        
        return totalSpeed / pathPoints.size();
    }
    
    /**
     * Получает последнюю точку пути
     */
    public VesselPathPoint getLastPoint() {
        return lastPoint;
    }
    
    /**
     * Получает количество точек пути
     */
    public int getPathPointsCount() {
        synchronized (pathPoints) {
            return pathPoints.size();
        }
    }
    
    /**
     * Очищает все точки пути
     */
    public void clearPath() {
        Log.i(TAG, "clearPath() вызван");
        
        synchronized (pathPoints) {
            int pointsCount = pathPoints.size();
            pathPoints.clear();
            lastPoint = null;
            Log.i(TAG, "Очищено " + pointsCount + " точек из памяти");
        }
        
        // Удаляем точки из SharedPreferences
        prefs.edit()
            .remove(KEY_PATH_POINTS)
            .putLong(KEY_LAST_UPDATE, System.currentTimeMillis())
            .apply();
        Log.i(TAG, "Путь очищен из памяти и SharedPreferences");
    }
    
    /**
     * Сохраняет точки пути в SharedPreferences
     */
    private void savePathPoints() {
        try {
            JSONArray jsonArray = new JSONArray();
            
            // Синхронизируем доступ к pathPoints для избежания гонки потоков
            synchronized (pathPoints) {
                for (VesselPathPoint point : pathPoints) {
                    JSONObject jsonPoint = new JSONObject();
                    jsonPoint.put("longitude", point.getLongitude());
                    jsonPoint.put("latitude", point.getLatitude());
                    jsonPoint.put("speed", point.getSpeed());
                    jsonPoint.put("timestamp", point.getTimestamp());
                    jsonArray.put(jsonPoint);
                }
            }
            
            prefs.edit()
                .putString(KEY_PATH_POINTS, jsonArray.toString())
                .putLong(KEY_LAST_UPDATE, System.currentTimeMillis())
                .apply();
                
            Log.d(TAG, "Сохранено " + pathPoints.size() + " точек пути");
            
        } catch (JSONException e) {
            Log.e(TAG, "Ошибка сохранения точек пути", e);
        }
    }
    
    /**
     * Загружает точки пути из SharedPreferences в фоновом потоке
     */
    private void loadPathPointsAsync() {
        new Thread(() -> {
            try {
                String jsonString = prefs.getString(KEY_PATH_POINTS, null);
                if (jsonString == null || jsonString.isEmpty()) {
                    Log.d(TAG, "Нет сохраненных точек пути");
                    return;
                }
                
                JSONArray jsonArray = new JSONArray(jsonString);
                List<VesselPathPoint> loadedPoints = new ArrayList<>();
                
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonPoint = jsonArray.getJSONObject(i);
                    VesselPathPoint point = new VesselPathPoint(
                        jsonPoint.getDouble("longitude"),
                        jsonPoint.getDouble("latitude"),
                        (float) jsonPoint.getDouble("speed"),
                        jsonPoint.getLong("timestamp")
                    );
                    loadedPoints.add(point);
                }
                
                // Обновляем UI поток через существующий Handler
                uiHandler.post(() -> {
                    synchronized (pathPoints) {
                        pathPoints.clear();
                        pathPoints.addAll(loadedPoints);
                        
                        // Устанавливаем последнюю точку
                        if (!pathPoints.isEmpty()) {
                            lastPoint = pathPoints.get(pathPoints.size() - 1);
                        }
                    }
                    Log.d(TAG, "Загружено " + loadedPoints.size() + " точек пути для судна " + vesselId);
                });
                
            } catch (Exception e) {
                Log.e(TAG, "Ошибка загрузки точек пути", e);
            }
        }).start();
    }
    
    /**
     * Загружает точки пути из SharedPreferences (синхронно)
     */
    private void loadPathPoints() {
        try {
            String jsonString = prefs.getString(KEY_PATH_POINTS, null);
            if (jsonString == null || jsonString.isEmpty()) {
                Log.d(TAG, "Нет сохраненных точек пути");
                return;
            }
            
            JSONArray jsonArray = new JSONArray(jsonString);
            pathPoints.clear();
            
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonPoint = jsonArray.getJSONObject(i);
                VesselPathPoint point = new VesselPathPoint(
                    jsonPoint.getDouble("longitude"),
                    jsonPoint.getDouble("latitude"),
                    (float) jsonPoint.getDouble("speed"),
                    jsonPoint.getLong("timestamp")
                );
                pathPoints.add(point);
            }
            
            // Устанавливаем последнюю точку
            if (!pathPoints.isEmpty()) {
                lastPoint = pathPoints.get(pathPoints.size() - 1);
            }
            
            Log.i(TAG, "Загружено " + pathPoints.size() + " точек пути");
            
        } catch (JSONException e) {
            Log.e(TAG, "Ошибка загрузки точек пути", e);
            pathPoints.clear();
        }
    }
    
    /**
     * Получает информацию о пути для отладки
     */
    public String getPathInfo() {
        synchronized (pathPoints) {
            if (pathPoints.isEmpty()) {
                return "Путь пуст";
            }
            
            VesselPathPoint first = pathPoints.get(0);
            VesselPathPoint last = pathPoints.get(pathPoints.size() - 1);
            
            return String.format("Путь: %d точек, от %s до %s, средняя скорость: %.1f узлов",
                               pathPoints.size(),
                               first.toString(),
                               last.toString(),
                               getAverageSpeed());
        }
    }
    
    /**
     * Проверяет валидность координат
     * Игнорирует координаты 0,0 и 181,91 (невалидные значения AIS)
     */
    private boolean isValidCoordinates(double latitude, double longitude) {
        // Проверяем на нулевые координаты
        if (latitude == 0.0 && longitude == 0.0) {
            return false;
        }
        
        // Проверяем на невалидные координаты AIS (181, 91)
        if (latitude == 91.0 && longitude == 181.0) {
            return false;
        }
        
        // Проверяем на стандартные границы координат
        if (latitude < -90.0 || latitude > 90.0) {
            return false;
        }
        
        if (longitude < -180.0 || longitude > 180.0) {
            return false;
        }
        
        return true;
    }
    
    /**
     * Очистка ресурсов
     */
    public void cleanup() {
        if (uiHandler != null) {
            uiHandler.removeCallbacksAndMessages(null);
            uiHandler = null;
        }
        Log.d(TAG, "VesselPathController очищен для судна " + vesselId);
    }
}
