using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ScaBox30.Controller
{
    /// <summary>
    /// Reemplazo del ReaderSearcher del SDK
    /// Busca sensores SR-X300W en la red mediante escaneo TCP
    /// </summary>
    public class TcpReaderSearcher : IDisposable
    {
        private bool isSearching = false;
        private List<NicSearchResult> nicList = new List<NicSearchResult>();

        public bool IsSearching => isSearching;
        public NicSearchResult SelectedNicSearchResult { get; set; }

        /// <summary>
        /// Lista las interfaces de red disponibles en el equipo
        /// Compatible con: m_nicList = m_searcher.ListUpNic()
        /// </summary>
        public List<NicSearchResult> ListUpNic()
        {
            nicList.Clear();

            try
            {
                foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
                {
                    // Filtrar solo interfaces activas y Ethernet/Wi-Fi
                    if (ni.OperationalStatus == OperationalStatus.Up &&
                        (ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
                         ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211))
                    {
                        IPInterfaceProperties ipProps = ni.GetIPProperties();

                        foreach (UnicastIPAddressInformation ip in ipProps.UnicastAddresses)
                        {
                            // Solo IPv4
                            if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                            {
                                var nicResult = new NicSearchResult
                                {
                                    NicIpAddr = ip.Address.ToString(),
                                    NicName = ni.Name,
                                    NicDescription = ni.Description
                                };

                                nicList.Add(nicResult);
                                Console.WriteLine($"[NIC] Encontrada: {nicResult.NicIpAddr} ({nicResult.NicName})");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[NIC] Error listando interfaces: {ex.Message}");
            }

            return nicList;
        }

        /// <summary>
        /// Inicia búsqueda de sensores en la red
        /// Compatible con: m_searcher.Start((res) => { ... })
        /// </summary>
        public void Start(Action<SearchResult> onSensorFound)
        {
            if (isSearching)
            {
                Console.WriteLine("[SEARCH] Ya hay una búsqueda en curso");
                return;
            }

            if (SelectedNicSearchResult == null)
            {
                Console.WriteLine("[SEARCH] ERROR: No se ha seleccionado una NIC");
                return;
            }

            isSearching = true;
            Console.WriteLine($"[SEARCH] Iniciando búsqueda desde {SelectedNicSearchResult.NicIpAddr}...");

            // Ejecutar búsqueda en background
            Task.Run(() => SearchSensorsInNetwork(onSensorFound));
        }

        /// <summary>
        /// Busca sensores SR-X300W en la red local
        /// Prueba conectar al puerto 9004 (puerto de comandos SR-X300W)
        /// </summary>
        private async void SearchSensorsInNetwork(Action<SearchResult> onSensorFound)
        {
            try
            {
                string localIP = SelectedNicSearchResult.NicIpAddr;
                string subnet = GetSubnet(localIP);
                int port = 9004; // Puerto TCP comandos SR-X300W

                Console.WriteLine($"[SEARCH] Escaneando subnet {subnet}.x en puerto {port}");

                // Escanear rango de IPs (ejemplo: 192.168.100.1 - 192.168.100.254)
                List<Task> scanTasks = new List<Task>();

                for (int i = 1; i <= 254; i++)
                {
                    string testIP = $"{subnet}.{i}";

                    // No probar la IP local
                    if (testIP == localIP)
                        continue;

                    // Lanzar escaneo asíncrono
                    scanTasks.Add(Task.Run(async () =>
                    {
                        if (await TryConnectToSensor(testIP, port, 500)) // 500ms timeout
                        {
                            Console.WriteLine($"[SEARCH] ✓ Sensor encontrado en {testIP}:{port}");

                            var result = new SearchResult
                            {
                                IpAddress = testIP,
                                Port = port,
                                IsResponding = true
                            };

                            onSensorFound?.Invoke(result);
                        }
                    }));

                    // Limitar concurrencia para no saturar la red
                    if (scanTasks.Count >= 20)
                    {
                        await Task.WhenAll(scanTasks);
                        scanTasks.Clear();
                    }
                }

                // Esperar tareas restantes
                await Task.WhenAll(scanTasks);

                Console.WriteLine("[SEARCH] Búsqueda completada");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[SEARCH] Error en búsqueda: {ex.Message}");
            }
            finally
            {
                isSearching = false;
            }
        }

        /// <summary>
        /// Intenta conectar a una IP:Puerto con timeout
        /// </summary>
        private async Task<bool> TryConnectToSensor(string ip, int port, int timeoutMs)
        {
            try
            {
                using (var client = new TcpClient())
                {
                    var connectTask = client.ConnectAsync(ip, port);
                    var timeoutTask = Task.Delay(timeoutMs);

                    if (await Task.WhenAny(connectTask, timeoutTask) == connectTask)
                    {
                        // Conexión exitosa
                        if (client.Connected)
                        {
                            // Verificar que responda a un comando básico
                            using (var stream = client.GetStream())
                            {
                                stream.ReadTimeout = 500;
                                byte[] testCmd = System.Text.Encoding.ASCII.GetBytes("NUM\r");
                                await stream.WriteAsync(testCmd, 0, testCmd.Length);

                                byte[] buffer = new byte[256];
                                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);

                                return bytesRead > 0; // Si responde, es un sensor válido
                            }
                        }
                    }
                }
            }
            catch
            {
                // Silenciosamente ignorar fallos (IP no responde)
            }

            return false;
        }

        /// <summary>
        /// Obtiene la subred de una IP (ejemplo: 192.168.100.1 -> 192.168.100)
        /// </summary>
        private string GetSubnet(string ip)
        {
            string[] parts = ip.Split('.');
            if (parts.Length == 4)
            {
                return $"{parts[0]}.{parts[1]}.{parts[2]}";
            }
            return "192.168.100"; // Fallback
        }

        /// <summary>
        /// Detiene la búsqueda
        /// </summary>
        public void Stop()
        {
            isSearching = false;
            Console.WriteLine("[SEARCH] Búsqueda detenida");
        }

        public void Dispose()
        {
            Stop();
        }
    }

    /// <summary>
    /// Resultado de búsqueda de NIC (compatible con SDK)
    /// </summary>
    public class NicSearchResult
    {
        public string NicIpAddr { get; set; }
        public string NicName { get; set; }
        public string NicDescription { get; set; }
    }

    /// <summary>
    /// Resultado de búsqueda de sensor
    /// </summary>
    public class SearchResult
    {
        public string IpAddress { get; set; }
        public int Port { get; set; }
        public bool IsResponding { get; set; }
    }
}