using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.SystemAlerts;
using EasyNetQ;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Diagnostics;

namespace adas_core.Infrastructure.Services;

public class SendAlertService(
    IOptions<RabbitMqSettings> rabbitMqSettings,
    ILogger<SendAlertService> logger)
    : ISendAlertService
{
    private readonly string _errorObservationsQueue = $"Error{rabbitMqSettings.Value.ObservationsQueue}";
    private readonly string _errorPatientsQueue = $"Error{rabbitMqSettings.Value.PatientsQueue}";
    private readonly string _errorPumpsQueue = $"Error{rabbitMqSettings.Value.PumpsQueue}";
    private readonly string _errorRecordingQueue = $"Error{rabbitMqSettings.Value.RecordingQueue}";
    private readonly string _errorTreatmetsQueue = $"Error{rabbitMqSettings.Value.TreatmentsQueue}";
    private readonly string? _rabbitConnectionString = rabbitMqSettings.Value.ConnectionString;


    //readonly PlatformID[] _windowsPlatforms;

    ////TODO new ws private static DefaultWebSocketHandler defaultWebSocketHandler = new ();        

    //_windowsPlatforms = new[]
    //{
    //    PlatformID.Win32NT,
    //    PlatformID.Win32S,
    //    PlatformID.Win32Windows,
    //    PlatformID.WinCE
    //};

    public async Task<List<Queue>> GetQueues()
    {
        if (_rabbitConnectionString != null) return await GetQueuesAsync();

        logger.LogError("Rabbit connection string not defined in web config");

        return [];
    }

    public List<Performance> GetPerformance()
    {
        logger.LogDebug("Starting check performance data from hospitals");

        var list = new List<Performance>();

        try
        {
            list.Add(GetConsumedCpu());
            list.Add(GetConsumedRam());
            list.AddRange(GetConsumedStorages());
        }
        catch (Exception e)
        {
            logger.LogError("Error check error performance data from hospitals: {eMessage} {eStackTrace}",
                e.Message, e.StackTrace);
        }

        return list;
    }

    public async Task<List<ApiClients>> GetApiClients()
    {
        return await GetApiClientsAsync();
    }

    private async Task<List<Queue>> GetQueuesAsync()
    {
        logger.LogDebug("Starting check rabbitMQ data from hospitals");

        var errorQueues = new List<Queue>();
        var errorQueuesNames = new List<string>();

        try
        {
            var services = new ServiceCollection();
            services.AddEasyNetQ(_rabbitConnectionString);

            var provider = services.BuildServiceProvider();
            var bus = provider.GetRequiredService<IBus>();

            var advanced = bus.Advanced;

            if (!string.IsNullOrEmpty(_errorRecordingQueue))
                errorQueuesNames.Add(_errorRecordingQueue);

            if (!string.IsNullOrEmpty(_errorPatientsQueue))
                errorQueuesNames.Add(_errorPatientsQueue);

            if (!string.IsNullOrEmpty(_errorTreatmetsQueue))
                errorQueuesNames.Add(_errorTreatmetsQueue);

            if (!string.IsNullOrEmpty(_errorObservationsQueue))
                errorQueuesNames.Add(_errorObservationsQueue);

            if (!string.IsNullOrEmpty(_errorPumpsQueue))
                errorQueuesNames.Add(_errorPumpsQueue);

            foreach (var errorQueueName in errorQueuesNames.Distinct())
            {
                var stats = await advanced.GetQueueStatsAsync(errorQueueName);

                errorQueues.Add(new Queue
                {
                    Name = errorQueueName,
                    Messages = stats.MessagesCount,
                    Consumers = stats.ConsumersCount
                });
            }
        }
        catch (Exception e)
        {
            logger.LogError("Error checking RabbitMQ queues: {msg} {stack}",
                e.Message, e.StackTrace);
        }

        return errorQueues;
    }

    public Performance GetConsumedCpu()
    {
        Performance performance = new();

        try
        {
            var currentProcess = Process.GetCurrentProcess();
            var percentage = currentProcess.TotalProcessorTime.TotalMilliseconds / Environment.ProcessorCount / 10;

            performance = new Performance
            {
                Name = "CPU",
                PercentageConsumed = percentage,
                ValueTotal = 100,
                Unit = "%"
            };
        }
        catch (Exception e)
        {
            logger.LogError("Error check CPU performance: {eMessage} {eStackTrace}", e.Message, e.StackTrace);
        }

        return performance;
    }

    public Performance GetConsumedRam()
    {
        Performance performance = new();
        try
        {
            var totalMemoryBytes = GC.GetTotalMemory(false);
            var totalMemoryGb = Math.Round((double)totalMemoryBytes / 1024 / 1024 / 1024, 2);

            performance = new Performance
            {
                Name = "RAM",
                ValueTotal = totalMemoryGb,
                ValueConsumed = totalMemoryGb,
                PercentageConsumed = 100,
                Unit = "GB"
            };
        }
        catch (Exception e)
        {
            logger.LogError("Error check RAM performance: {eMessage} {eStackTrace}", e.Message, e.StackTrace);
        }

        return performance;
    }


    public Performance GetConsumedStorage(DriveInfo drive)
    {
        Performance performance = new();
        try
        {
            double percentage = 0;

            //Total storage
            double valueTotal = drive.TotalSize;

            //Consumed storage
            var value = valueTotal - drive.AvailableFreeSpace;

            if (valueTotal != 0)
            {
                percentage = Math.Round(value * 100 / valueTotal, 2); //%

                valueTotal = Math.Round(valueTotal / 1024 / 1024 / 1024, 2); //Bytes -> GB
            }

            value = Math.Round(value / 1024 / 1024 / 1024, 2); //Bytes -> GB

            performance = new Performance
            {
                Name = "STORAGE " + drive.Name,
                ValueConsumed = value,
                ValueTotal = valueTotal,
                PercentageConsumed = percentage,
                Unit = "GB"
            };
        }
        catch (Exception e)
        {
            logger.LogError("Error check Storage performance: {eMessage} {eStackTrace}", e.Message, e.StackTrace);
        }

        return performance;
    }

    private List<Performance> GetConsumedStorages()
    {
        var list = new List<Performance>();
        try
        {
            foreach (var drive in DriveInfo.GetDrives())
            {
                if (!drive.IsReady) continue;
                try
                {
                    var performance = GetConsumedStorage(drive);
                    list.Add(performance);
                }
                catch (Exception e)
                {
                    logger.LogError("Error check Storage drive {drive} in performance: {eMessage}", drive.Name,
                        e.Message);
                }
            }
        }
        catch (Exception e)
        {
            logger.LogError("Error check Storages performance: {eMessage}", e.Message);
        }

        return list;
    }


    private async Task<List<ApiClients>> GetApiClientsAsync()
    {
        logger.LogDebug("Starting check conected clients from hospitals");

        var clientsList = new List<ApiClients>();

        try
        {
            var clients = await GetWebSocketClients();
            if (clients != null)
                clientsList.Add(clients);
        }
        catch (Exception e)
        {
            logger.LogError("Error check error conected clients from hospitals: {eMessage} {eStackTrace}",
                e.Message, e.StackTrace);
        }

        return clientsList;
    }

    private Task<ApiClients?> GetWebSocketClients()
    {
        ApiClients apiClients = new();

        try
        {
            //TODO new ws apiClients = defaultWebSocketHandler.GetSubscribersConected();

            //apiClients = webSocketHandler.GetSubscribersConected();                
        }
        catch (Exception e)
        {
            logger.LogError("Error check WebSocket Clients: {eMessage} {eStackTrace}", e.Message, e.StackTrace);
        }

        return Task.FromResult<ApiClients?>(apiClients);
    }
}