using Insight.Agent.Interfaces;
using Insight.Agent.Messages;
using System.Management;
using System.Runtime.Versioning;

namespace Insight.Agent.Network.Handlers
{
    [SupportedOSPlatform("windows")]
    public class MemoryHandler : IAgentMessageHandler<AgentSession>
    {
        public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
        {
            if (message is GetInventory)
            {
                var result = new MemoryList();
                result.AddRange(GetMemory());

                await sender.SendAsync(result, cancellationToken);
            }
        }

        private static List<Memory> GetMemory()
        {
            using var searcher = new ManagementObjectSearcher
            {
                Scope = new ManagementScope(@"root\cimv2"),
                Query = new ObjectQuery("select tag, devicelocator, manufacturer, partnumber, serialnumber, capacity, speed, maxvoltage, configuredclockspeed, configuredvoltage from win32_physicalmemory")
            };

            if (searcher.TryGet(out var collection) is false)
            {
                searcher.Query = new ObjectQuery("select * from win32_physicalmemory");

                if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL");
            }

            var memorysticks = new List<Memory>();

            using (collection)
            {
                uint index = 0;

                foreach (ManagementObject @object in collection.Cast<ManagementObject>())
                {
                    var @memory = new Memory();

                    var properties = @object.GetPropertyHashes();

                    @memory.Index = index;
                    @memory.Tag = @object.GetValue<string>(properties, "tag")?.Trim();
                    @memory.Location = @object.GetValue<string>(properties, "devicelocator")?.Trim();
                    @memory.Manufacturer = @object.GetValue<string>(properties, "manufacturer")?.Trim();
                    @memory.Model = @object.GetValue<string>(properties, "partnumber")?.Trim();
                    @memory.Serial = @object.GetValue<string>(properties, "serialnumber")?.Trim();
                    @memory.Capacity = @object.GetValue<ulong>(properties, "capacity");
                    @memory.Speed = @object.GetValue<uint>(properties, "speed");
                    @memory.Voltage = @object.GetValue<uint>(properties, "maxvoltage");
                    @memory.ConfiguredSpeed = @object.GetValue<uint>(properties, "configuredclockspeed");
                    @memory.ConfiguredVoltage = @object.GetValue<uint>(properties, "configuredvoltage");

                    memorysticks.Add(@memory);
                    index++;
                }
            }

            return memorysticks;
        }

        //private async ValueTask<Memory.Metric> GetMemoryMetricAsync(CancellationToken cancellationToken)
        //{
        //    var metric = new Memory.Metric();

        //    using var searcher = new ManagementObjectSearcher
        //    {
        //        Scope = new ManagementScope(@"root\cimv2"),
        //        Query = new ObjectQuery("select totalphysicalmemory from win32_computersystem")
        //    };

        //    if (searcher.TryGet(out var collection) is false)
        //    {
        //        searcher.Query = new ObjectQuery("select * from win32_computersystem");

        //        if (searcher.TryGet(out collection) is false) return metric;
        //    }

        //    ulong capacity = 0;

        //    using (collection)
        //    {
        //        foreach (var @object in collection)
        //        {
        //            var properties = @object.GetPropertyHashes();

        //            if (@object.TryGetValue(properties, "totalphysicalmemory", out capacity))
        //            {
        //                capacity = capacity / 1024 / 1024;
        //            }

        //            break;
        //        }
        //    }

        //    if (MemoryAvailableCounter is null)
        //    {
        //        MemoryAvailableCounter = new PerformanceCounter
        //        {
        //            CategoryName = "Memory",
        //            CounterName = "Available MBytes"
        //        };

        //        metric.MemoryAvailable = MemoryAvailableCounter.NextValue();
        //        await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
        //    }

        //    metric.Timestamp = DateTime.Now;
        //    metric.MemoryAvailable = MemoryAvailableCounter.NextValue();
        //    metric.MemoryUsed = capacity - metric.MemoryAvailable;
        //    metric.MemoryUsagePercentage = metric.MemoryUsed / capacity * 100;
        //    metric.MemoryAvailablePercentage = 100 - metric.MemoryUsagePercentage;
        //    return metric;
        //}
    }
}