package com.grigowashere.aismap.controllers;

import android.util.Log;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Контроллер для прослушивания UDP портов
 */
public class UDPListener {
    
    private static final String TAG = "UDPListener";
    private static final int BUFFER_SIZE = 1024;
    
    private int port;
    private DatagramSocket socket;
    private ExecutorService executor;
    private AtomicBoolean isRunning;
    private UDPListenerCallback callback;
    
    public interface UDPListenerCallback {
        void onDataReceived(String data, String sourceAddress, int sourcePort);
        void onUDPError(String error);
    }
    
    public UDPListener(int port) {
        this.port = port;
        this.executor = Executors.newSingleThreadExecutor();
        this.isRunning = new AtomicBoolean(false);
    }
    
    public void setCallback(UDPListenerCallback callback) {
        this.callback = callback;
    }
    
    /**
     * Запускает прослушивание UDP порта
     */
    public void start() {
        if (isRunning.get()) {
            Log.w(TAG, "UDP слушатель уже запущен");
            return;
        }
        
        executor.execute(() -> {
            try {
                socket = new DatagramSocket(port);
                isRunning.set(true);
                Log.i(TAG, "UDP слушатель запущен на порту " + port);
                
                while (isRunning.get()) {
                    byte[] buffer = new byte[BUFFER_SIZE];
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    
                    try {
                        socket.receive(packet);
                        String data = new String(packet.getData(), 0, packet.getLength());
                        String sourceAddress = packet.getAddress().getHostAddress();
                        int sourcePort = packet.getPort();
                        
                        if (callback != null) {
                            callback.onDataReceived(data, sourceAddress, sourcePort);
                        }
                        
                        Log.d(TAG, "Получены данные от " + sourceAddress + ":" + sourcePort + ": " + data);
                        
                    } catch (IOException e) {
                        if (isRunning.get()) {
                            Log.e(TAG, "Ошибка при получении UDP пакета: " + e.getMessage());
                            if (callback != null) {
                                callback.onUDPError("Ошибка UDP: " + e.getMessage());
                            }
                        }
                    }
                }
                
            } catch (IOException e) {
                Log.e(TAG, "Ошибка при создании UDP сокета: " + e.getMessage());
                if (callback != null) {
                    callback.onUDPError("Не удалось создать UDP сокет: " + e.getMessage());
                }
            } finally {
                stop();
            }
        });
    }
    
    /**
     * Останавливает прослушивание UDP порта
     */
    public void stop() {
        isRunning.set(false);
        
        if (socket != null && !socket.isClosed()) {
            socket.close();
            socket = null;
        }
        
        Log.i(TAG, "UDP слушатель остановлен");
    }
    
    /**
     * Отправляет UDP пакет
     */
    public void sendData(String data, String targetAddress, int targetPort) {
        if (socket == null || socket.isClosed()) {
            Log.w(TAG, "UDP сокет не создан");
            return;
        }
        
        executor.execute(() -> {
            try {
                byte[] buffer = data.getBytes();
                InetAddress address = InetAddress.getByName(targetAddress);
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, targetPort);
                
                socket.send(packet);
                Log.d(TAG, "Отправлены данные на " + targetAddress + ":" + targetPort + ": " + data);
                
            } catch (IOException e) {
                Log.e(TAG, "Ошибка при отправке UDP пакета: " + e.getMessage());
                if (callback != null) {
                    callback.onUDPError("Ошибка отправки UDP: " + e.getMessage());
                }
            }
        });
    }
    
    /**
     * Проверяет, запущен ли слушатель
     */
    public boolean isRunning() {
        return isRunning.get();
    }
    
    /**
     * Получает текущий порт
     */
    public int getPort() {
        return port;
    }
    
    /**
     * Устанавливает новый порт
     */
    public void setPort(int port) {
        if (isRunning.get()) {
            Log.w(TAG, "Нельзя изменить порт во время работы");
            return;
        }
        this.port = port;
    }
    
    /**
     * Освобождает ресурсы
     */
    public void cleanup() {
        stop();
        if (executor != null && !executor.isShutdown()) {
            executor.shutdown();
        }
    }
}
