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

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

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

        private static List<Processor> GetProcessors()
        {
            using var searcher = new ManagementObjectSearcher
            {
                Scope = new ManagementScope(@"root\cimv2"),
                Query = new ObjectQuery("select deviceid, name, manufacturer, socketdesignation, version, processorid, l2cachesize, l3cachesize, currentclockspeed, maxclockspeed, numberofcores, numberoflogicalprocessors, virtualizationfirmwareenabled from win32_processor")
            };

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

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

            var processors = new List<Processor>();

            using (collection)
            {
                uint index = 0;

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

                    var properties = @object.GetPropertyHashes();

                    processor.Index = index;
                    processor.DeviceId = @object.GetValue<string>(properties, "deviceid")?.Trim();
                    processor.Name = @object.GetValue<string>(properties, "name")?.Trim();
                    processor.Manufacturer = @object.GetValue<string>(properties, "manufacturer")?.Trim();
                    processor.Socket = @object.GetValue<string>(properties, "socketdesignation")?.Trim();
                    processor.Version = @object.GetValue<string>(properties, "version")?.Trim();
                    processor.SerialNumber = @object.GetValue<string>(properties, "processorid")?.Trim();
                    processor.CurrentSpeed = @object.GetValue<uint>(properties, "currentclockspeed");
                    processor.MaxSpeed = @object.GetValue<uint>(properties, "maxclockspeed");
                    processor.Cores = @object.GetValue<uint>(properties, "numberofcores");
                    processor.LogicalCores = @object.GetValue<uint>(properties, "numberoflogicalprocessors");
                    processor.Virtualization = @object.GetValue<bool>(properties, "virtualizationfirmwareenabled");

                    searcher.Query = new ObjectQuery("select level, maxcachesize from win32_cachememory");

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

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

                    using (collection2)
                    {
                        foreach (ManagementObject @object2 in collection2.Cast<ManagementObject>())
                        {
                            var properties2 = @object2.GetPropertyHashes();

                            ProcessorCacheLevelEnum? cacheLevel = null;

                            cacheLevel = (ProcessorCacheLevelEnum?)@object2.GetValue<ushort>(properties2, "level");

                            if (cacheLevel is null) continue;

                            var installedSize = @object2.GetValue<uint>(properties2, "maxcachesize");

                            switch (cacheLevel)
                            {
                                case ProcessorCacheLevelEnum.L1:
                                    {
                                        processor.L1Size = installedSize;
                                        break;
                                    }
                                case ProcessorCacheLevelEnum.L2:
                                    {
                                        processor.L2Size = installedSize;
                                        break;
                                    }
                                case ProcessorCacheLevelEnum.L3:
                                    {
                                        processor.L3Size = installedSize;
                                        break;
                                    }
                            }
                        }
                    }

                    processors.Add(processor);
                    index++;
                }
            }

            return processors;
        }

        private enum ProcessorCacheLevelEnum
        {
            L1 = 3,
            L2 = 4,
            L3 = 5,
        }

        //private async ValueTask<Processor.Metric?> GetProcessorMetricAsync(CancellationToken cancellationToken)
        //{
        //    var metric = new Processor.Metric();

        //    if (ProcessorTimeCounter is null)
        //    {
        //        ProcessorTimeCounter = new PerformanceCounter
        //        {
        //            CategoryName = "Processor",
        //            CounterName = "% Processor Time",
        //            InstanceName = "_Total"
        //        };

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

        //    metric.Timestamp = DateTime.Now;
        //    metric.ProcessorUsagePercentage = ProcessorTimeCounter?.NextValue();
        //    return metric;
        //}
    }
}