using Insight.Agent.Interfaces;
using Insight.Agent.Messages;
using Microsoft.Win32;
using System.Management;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.AccessControl;

namespace Insight.Agent.Network.Handlers
{
    [SupportedOSPlatform("windows")]
    public class OperationSystemHandler : IAgentMessageHandler<AgentSession>
    {
        public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
        {
            if (message is GetInventory)
            {
                await sender.SendAsync(GetOperatingSystem(), cancellationToken);
            }
        }

        private static OperationSystem GetOperatingSystem()
        {
            using var searcher = new ManagementObjectSearcher
            {
                Scope = new ManagementScope(@"root\cimv2"),
                Query = new ObjectQuery("select caption, version, serialnumber, osarchitecture, installdate from win32_operatingsystem")
            };

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

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

            var os = new OperationSystem();

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

                    os.Name = @object.GetValue<string>(properties, "caption")?.Trim();
                    os.Version = @object.GetValue<string>(properties, "version")?.Trim();
                    os.SerialNumber = @object.GetValue<string>(properties, "serialnumber")?.Trim();

                    if (@object.TryGetValue<string>(properties, "osarchitecture", out var architecture))
                    {
                        if (architecture is not null && architecture.ToLower().Contains("64")) os.Architecture = Architecture.X64;
                    }
                    else
                    {
                        os.Architecture = Architecture.X86;
                    }

                    if (@object.TryGetValue<object>(properties, "installdate", out var installdate))
                    {
                        os.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString());
                    }

                    break;
                }
            }

            using var registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default);
            using var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey);

            if (key is not null && key?.GetValue("UBR")?.ToString() is string buildNumber)
            {
                os.Version = $"{os.Version}.{buildNumber}";
            }

            searcher.Query = new ObjectQuery("select * from win32_portconnector");

            if (searcher.TryGet(out var collection2) is false)
            {
                os.Virtual = true;
            }
            else
            {
                os.Virtual = false;
            }

            collection2.Dispose();

            return os;
        }
    }
}