package com.grigowashere.aismap.utils;

import android.util.Log;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Утилита для отправки логов на внешний ресурс
 * Отправляет пакеты логов раз в секунду на https://ais.grigowashere.ru/logs/batch
 */
public class LogSender {
    
    private static final String TAG = "LogSender";
    private static final String BASE_URL = "https://ais.grigowashere.ru";

    /**
     * Временно отключено, чтобы не создавать сетевой шум и фоновые потоки.
     * Если снова понадобится — переключить в true или завязать на настройку/BuildConfig.
     */
    private static final boolean ENABLED = false;
    
    // Мягкие цвета для лучшей читаемости на фоне #364758
    private static final String COLOR_SOFT_BLUE = "#8AB4F8"; // мягкий синий
    private static final String COLOR_SOFT_RED = "#FF8A80";  // мягкий красный
    
    // Настройки генерации цветов для кораблей
    private static final float VESSEL_COLOR_SATURATION = 0.4f; // Низкая насыщенность для мягкости
    private static final float VESSEL_COLOR_VALUE = 0.75f;     // Средняя яркость для контраста с темным фоном
    
    // Буферизация логов
    private static final List<LogEntry> logBuffer = new ArrayList<>();
    private static final Object bufferLock = new Object();
    private static volatile ScheduledExecutorService scheduler = null;
    private static volatile boolean schedulerStarted = false;

    /**
     * Структура для хранения лога
     */
    private static class LogEntry {
        String type;
        String message;
        String color;
        long timestamp;
        
        LogEntry(String type, String message, String color) {
            this.type = type;
            this.message = message;
            this.color = color;
            this.timestamp = System.currentTimeMillis();
        }
    }

    /**
     * Инициализирует планировщик отправки логов
     */
    private static void startScheduler() {
        if (!ENABLED) {
            return;
        }
        if (!schedulerStarted) {
            synchronized (LogSender.class) {
                if (!schedulerStarted) {
                    if (scheduler == null || scheduler.isShutdown()) {
                        scheduler = Executors.newSingleThreadScheduledExecutor();
                    }
                    scheduler.scheduleAtFixedRate(() -> {
                        sendBufferedLogs();
                    }, 1, 1, TimeUnit.SECONDS);
                    schedulerStarted = true;
                    Log.d(TAG, "Планировщик отправки логов запущен (каждую секунду)");
                }
            }
        }
    }

    /**
     * Добавляет лог в буфер
     */
    private static void addToBuffer(String type, String message, String color) {
        if (!ENABLED) {
            return;
        }
        synchronized (bufferLock) {
            logBuffer.add(new LogEntry(type, message, color));
        }
        startScheduler(); // Запускаем планировщик при первом логе
    }

    /**
     * Отправляет все накопленные логи пакетом
     */
    private static void sendBufferedLogs() {
        if (!ENABLED) {
            return;
        }
        List<LogEntry> logsToSend;
        synchronized (bufferLock) {
            if (logBuffer.isEmpty()) {
                return;
            }
            logsToSend = new ArrayList<>(logBuffer);
            logBuffer.clear();
        }
        
        if (logsToSend.isEmpty()) {
            return;
        }
        
        Log.d(TAG, "Отправляем пакет из " + logsToSend.size() + " логов");
        sendLogsBatch(logsToSend);
    }

    /**
     * Отправляет пакет логов через POST запрос
     */
    private static void sendLogsBatch(List<LogEntry> logs) {
        if (!ENABLED) {
            return;
        }
        HttpURLConnection connection = null;
        try {
            URL url = new URL(BASE_URL + "/api/logs/batch");
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("User-Agent", "AISMap/1.0");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(10000);
            connection.setDoOutput(true);
            
            // Формируем JSON
            StringBuilder json = new StringBuilder("{\"logs\":[");
            for (int i = 0; i < logs.size(); i++) {
                LogEntry log = logs.get(i);
                if (i > 0) json.append(",");
                json.append("{")
                    .append("\"type\":\"").append(log.type).append("\",")
                    .append("\"message\":\"").append(log.message.replace("\"", "\\\"")).append("\",")
                    .append("\"color\":\"").append(log.color).append("\",")
                    .append("\"timestamp\":").append(log.timestamp)
                    .append("}");
            }
            json.append("]}");
            
            // Отправляем JSON
            try (OutputStream os = connection.getOutputStream()) {
                os.write(json.toString().getBytes(StandardCharsets.UTF_8));
            }
            
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                Log.d(TAG, "Пакет из " + logs.size() + " логов успешно отправлен");
            } else {
                Log.w(TAG, "Пакет логов отправлен с предупреждением, код ответа: " + responseCode);
            }
            
        } catch (IOException e) {
            Log.e(TAG, "Ошибка отправки пакета логов: " + e.getMessage(), e);
            // Возвращаем логи в буфер при ошибке
            synchronized (bufferLock) {
                logBuffer.addAll(0, logs); // Добавляем в начало буфера
            }
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
    
    /**
     * Отправляет лог NMEA сообщения
     * @param nmeaMessage NMEA сообщение
     */
    public static void logNMEA(String nmeaMessage) {
        if (!ENABLED) {
            return;
        }
        if (nmeaMessage == null || nmeaMessage.trim().isEmpty()) {
            return;
        }
        addToBuffer("nmea", nmeaMessage, COLOR_SOFT_BLUE);
    }
    
    /**
     * Отправляет лог обновления информации о корабле
     * @param mmsi MMSI корабля
     * @param vesselInfo Информация о корабле
     */
    public static void logShipUpdate(String mmsi, String vesselInfo) {
        if (!ENABLED) {
            return;
        }
        if (mmsi == null || mmsi.trim().isEmpty()) {
            return;
        }
                String message = "MMSI: " + mmsi;
                if (vesselInfo != null && !vesselInfo.trim().isEmpty()) {
                    message += " | " + vesselInfo;
                }
        addToBuffer("ships", message, generateVesselColor(mmsi));
    }
    
    /**
     * Отправляет лог обновления информации о корабле с заданным цветом
     * @param mmsi MMSI корабля
     * @param vesselInfo Информация о корабле
     * @param color Цвет лога
     */
    public static void logShipUpdate(String mmsi, String vesselInfo, String color) {
        if (!ENABLED) {
            return;
        }
        if (mmsi == null || mmsi.trim().isEmpty()) {
            return;
        }
                String message = "MMSI: " + mmsi;
                if (vesselInfo != null && !vesselInfo.trim().isEmpty()) {
                    message += " | " + vesselInfo;
                }
        addToBuffer("ships", message, color != null ? color : generateVesselColor(mmsi));
    }

    /**
     * Отправляет кастомный лог
     * @param logName Имя лога
     * @param message Сообщение
     * @param color Цвет
     */
    public static void logCustom(String logName, String message, String color) {
        if (!ENABLED) {
            return;
        }
        if (logName == null || message == null || message.trim().isEmpty()) {
            return;
        }
        addToBuffer(logName, message, color != null ? color : COLOR_SOFT_BLUE);
    }

    /**
     * Генерирует уникальный мягкий цвет для корабля на основе MMSI
     * Оптимизирован для читаемости на фоне #364758
     */
    private static String generateVesselColor(String mmsi) {
        if (mmsi == null || mmsi.trim().isEmpty()) {
            return COLOR_SOFT_BLUE;
        }
        
        try {
            long mmsiLong = Long.parseLong(mmsi);
            // Используем MMSI для генерации цвета
            int hash = (int) (mmsiLong % 360);
            
            // Генерируем мягкий цвет в HSV для фона #364758
            float hue = hash;
            float saturation = VESSEL_COLOR_SATURATION; // Низкая насыщенность для мягкости
            float value = VESSEL_COLOR_VALUE; // Средняя яркость для контраста с темным фоном
            
            // Конвертируем HSV в RGB (Android-совместимая реализация)
            float[] rgb = hsvToRgb(hue / 360f, saturation, value);
            int red = Math.round(rgb[0] * 255);
            int green = Math.round(rgb[1] * 255);
            int blue = Math.round(rgb[2] * 255);
            
            return String.format("#%02X%02X%02X", red, green, blue);
        } catch (NumberFormatException e) {
            // Если MMSI не число, используем хеш строки
            int hash = Math.abs(mmsi.hashCode()) % 360;
            float hue = hash;
            float saturation = VESSEL_COLOR_SATURATION; // Низкая насыщенность для мягкости
            float value = VESSEL_COLOR_VALUE; // Средняя яркость для контраста с темным фоном
            
            float[] rgb = hsvToRgb(hue / 360f, saturation, value);
            int red = Math.round(rgb[0] * 255);
            int green = Math.round(rgb[1] * 255);
            int blue = Math.round(rgb[2] * 255);
            
            return String.format("#%02X%02X%02X", red, green, blue);
        }
    }
    
    /**
     * Конвертирует HSV в RGB (Android-совместимая реализация)
     */
    private static float[] hsvToRgb(float h, float s, float v) {
        float[] rgb = new float[3];
        
        if (s == 0) {
            // Оттенки серого
            rgb[0] = rgb[1] = rgb[2] = v;
        } else {
            float c = v * s;
            float x = c * (1 - Math.abs((h * 6) % 2 - 1));
            float m = v - c;
            
            if (h < 1f/6f) {
                rgb[0] = c; rgb[1] = x; rgb[2] = 0;
            } else if (h < 2f/6f) {
                rgb[0] = x; rgb[1] = c; rgb[2] = 0;
            } else if (h < 3f/6f) {
                rgb[0] = 0; rgb[1] = c; rgb[2] = x;
            } else if (h < 4f/6f) {
                rgb[0] = 0; rgb[1] = x; rgb[2] = c;
            } else if (h < 5f/6f) {
                rgb[0] = x; rgb[1] = 0; rgb[2] = c;
            } else {
                rgb[0] = c; rgb[1] = 0; rgb[2] = x;
            }
            
            rgb[0] += m;
            rgb[1] += m;
            rgb[2] += m;
        }
        
        return rgb;
    }

    /**
     * Логирует ошибки парсинга NMEA сообщений
     */
    public static void logError(String errorType, String message, String details) {
        if (!ENABLED) {
            return;
        }
        String timestamp = java.time.LocalDateTime.now().format(
            java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        
        String logMessage = String.format(java.util.Locale.US,
            "[%s] %s: %s | Details: %s",
            timestamp, errorType, message, details);
        
        addToBuffer("errors", logMessage, COLOR_SOFT_RED);
    }

    /**
     * Логирует отброшенное NMEA сообщение
     */
    public static void logDroppedNMEA(String reason, String nmeaMessage, String details) {
        if (!ENABLED) {
            return;
        }
        logError("DROPPED_NMEA", 
            String.format("Отброшено NMEA сообщение: %s", reason),
            String.format("Message: %s | %s", 
                nmeaMessage != null ? nmeaMessage.substring(0, Math.min(100, nmeaMessage.length())) : "null",
                details != null ? details : ""));
    }

    /**
     * Логирует ошибку парсинга AIS
     */
    public static void logAISParseError(String error, String aisMessage, String details) {
        if (!ENABLED) {
            return;
        }
        logError("AIS_PARSE_ERROR", 
            String.format("Ошибка парсинга AIS: %s", error),
            String.format("AIS: %s | %s", 
                aisMessage != null ? aisMessage.substring(0, Math.min(100, aisMessage.length())) : "null",
                details != null ? details : ""));
    }

    /**
     * Логирует ошибку парсинга AIS с полным NMEA сообщением
     */
    public static void logAISParseErrorWithFullNMEA(String error, String fullNMEAMessage, String aisPayload, String details) {
        if (!ENABLED) {
            return;
        }
        logError("AIS_PARSE_ERROR", 
            String.format("Ошибка парсинга AIS: %s", error),
            String.format("Full NMEA: %s | AIS Payload: %s | %s", 
                fullNMEAMessage != null ? fullNMEAMessage : "null",
                aisPayload != null ? aisPayload.substring(0, Math.min(100, aisPayload.length())) : "null",
                details != null ? details : ""));
    }

    /**
     * Логирует ошибку BLE соединения
     */
    public static void logBLEError(String error, String deviceMac, String details) {
        if (!ENABLED) {
            return;
        }
        logError("BLE_ERROR", 
            String.format("Ошибка BLE: %s", error),
            String.format("Device: %s | %s", 
                deviceMac != null ? deviceMac : "unknown",
                details != null ? details : ""));
    }

    /**
     * Логирует полученный BLE кусок данных
     */
    public static void logBLEDataChunk(String deviceMac, String dataChunk) {
        if (!ENABLED) {
            return;
        }
        if (dataChunk == null || dataChunk.trim().isEmpty()) {
            return;
        }
        String message = "BLE Data from " + (deviceMac != null ? deviceMac : "unknown") + ": " + dataChunk;
        addToBuffer("ble", message, COLOR_SOFT_BLUE);
    }

    /**
     * Получает количество логов в буфере
     */
    public static int getBufferSize() {
        if (!ENABLED) {
            return 0;
        }
        synchronized (bufferLock) {
            return logBuffer.size();
        }
    }
    
    /**
     * Принудительно отправляет все накопленные логи
     */
    public static void flushLogs() {
        if (!ENABLED) {
            return;
        }
        sendBufferedLogs();
    }

    /**
     * Останавливает планировщик (вызывать при завершении приложения)
     */
    public static void shutdown() {
        if (!ENABLED) {
            return;
        }
        if (scheduler != null) {
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(2, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * Тестовый метод для демонстрации мягких цветов кораблей
     * Можно использовать для проверки читаемости на фоне #364758
     */
    public static void testVesselColors() {
        if (!ENABLED) {
            return;
        }
        String[] testMMSIs = {"123456789", "987654321", "555666777", "111222333", "999888777"};
        
        Log.d(TAG, "=== Тест мягких цветов для кораблей (фон #364758) ===");
        for (String mmsi : testMMSIs) {
            String color = generateVesselColor(mmsi);
            Log.d(TAG, String.format("MMSI %s -> цвет %s", mmsi, color));
        }
      //  Log.d(TAG, "=== Настройки: насыщенность=%.1f, яркость=%.1f ===",VESSEL_COLOR_SATURATION, VESSEL_COLOR_VALUE);
    }
}