using Insight.Agent.Interfaces;
using Insight.Agent.Messages;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using WUApiLib;
using static Insight.Agent.Messages.Update;

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

        private static UpdateList GetUpdates()
        {
            return new UpdateList
            {
                Installed = QueryInstalledUpdates(),
                Pending = QueryPendingUpdates()
            };
        }

        private static List<Update> QueryInstalledUpdates()
        {
            var updates = new List<Update>();

            var session = new UpdateSessionClass();
            var searcher = session.CreateUpdateSearcher();
            searcher.Online = false;

            var count = searcher.GetTotalHistoryCount();
            var result = searcher.QueryHistory(0, count);

            foreach (IUpdateHistoryEntry wupdate in result)
            {
                var update = new Update
                {
                    Id = wupdate.UpdateIdentity.UpdateID,
                    Date = wupdate.Date,
                    Name = wupdate.Title,
                    Description = wupdate.Description,
                    Result = wupdate.ResultCode switch
                    {
                        OperationResultCode.orcNotStarted => OsUpdateResultCodeEnum.NotStarted,
                        OperationResultCode.orcInProgress => OsUpdateResultCodeEnum.InProgress,
                        OperationResultCode.orcSucceeded => OsUpdateResultCodeEnum.Succeeded,
                        OperationResultCode.orcSucceededWithErrors => OsUpdateResultCodeEnum.SucceededWithErrors,
                        OperationResultCode.orcFailed => OsUpdateResultCodeEnum.Failed,
                        OperationResultCode.orcAborted => OsUpdateResultCodeEnum.Aborted,
                        _ => null
                    },
                    SupportUrl = wupdate.SupportUrl,
                };

                try
                {
                    var rx = new Regex(@"KB(\d+)");
                    update.Hotfix = rx.Match(wupdate.Title).Value;
                }
                catch (Exception)
                {

                }

                updates.Add(update);
            }

            return updates;
        }

        private static List<Update> QueryPendingUpdates()
        {
            var updates = new List<Update>();

            var session = new UpdateSessionClass();
            var searcher = session.CreateUpdateSearcher();
            searcher.Online = true;

            var result = searcher.Search("IsInstalled=0");

            foreach (IUpdate wupdate in result.Updates)
            {
                var update = new Update
                {
                    Id = wupdate.Identity.UpdateID,
                    Type = wupdate.Type switch
                    {
                        UpdateType.utSoftware => OsUpdateTypeEnum.Software,
                        UpdateType.utDriver => OsUpdateTypeEnum.Driver,
                        _ => null
                    },
                    Date = wupdate.LastDeploymentChangeTime,
                    Name = wupdate.Title,
                    Description = wupdate.Description,
                    SupportUrl = wupdate.SupportUrl,
                    Size = wupdate.MaxDownloadSize,
                    IsDownloaded = wupdate.IsDownloaded,
                    CanRequestUserInput = wupdate.InstallationBehavior.CanRequestUserInput,
                    RebootBehavior = wupdate.InstallationBehavior.RebootBehavior switch
                    {
                        InstallationRebootBehavior.irbNeverReboots => OsUpdateRebootBehaviorEnum.NeverReboots,
                        InstallationRebootBehavior.irbAlwaysRequiresReboot => OsUpdateRebootBehaviorEnum.AlwaysRequiresReboot,
                        InstallationRebootBehavior.irbCanRequestReboot => OsUpdateRebootBehaviorEnum.CanRequestReboot,
                        _ => null
                    },
                };

                if (wupdate.KBArticleIDs.Count > 0)
                {
                    foreach (var id in wupdate.KBArticleIDs)
                    {
                        update.Hotfix = $"KB{id}";
                        break;
                    }
                }

                updates.Add(update);
            }

            return updates;
        }
    }
}