using Insight.Agent.Messages;
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Server.Extensions;
using Insight.Server.Network;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
using Vaitr.Network;

namespace Insight.Server.Services
{
    internal class JobService : BackgroundService
    {
        private readonly TcpSessionPool<AgentSession, MemPackSerializer, IAgentMessage> _agentPool;
        private readonly IMongoDatabase _database;
        private readonly ILogger<JobService> _logger;

        public JobService(TcpSessionPool<AgentSession, MemPackSerializer, IAgentMessage> agentPool, IMongoDatabase database, ILogger<JobService> logger)
        {
            _agentPool = agentPool;
            _database = database;
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken cancellationToken)
        {
            _logger.LogTrace("ExecuteAsync");

            await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);

            var jobs = new List<Task>
            {
                Task.Run(async () =>
                {
                    while (cancellationToken.IsCancellationRequested is false)
                    {
                        try
                        {
                            foreach (var agent in await GetAssignedAgentsAsync(cancellationToken))
                            {
                                await agent.SendAsync(new GetInventory(), cancellationToken);
                            }
                        }
                        catch (OperationCanceledException) { }
                        catch (Exception) { }
                        finally
                        {
                            await Task.Delay(TimeSpan.FromHours(1), cancellationToken);
                        }
                    }
                }, default)
            };

            try
            {
                await Task.WhenAll(jobs).ConfigureAwait(false);
            }
            catch (OperationCanceledException) { }
            catch (Exception) { }
        }

        private async ValueTask<IEnumerable<AgentSession>> GetAssignedAgentsAsync(CancellationToken cancellationToken)
        {
            var valid = new List<AgentSession>();

            await Async.ParallelForEach(_agentPool.Where(p => p.Value.Id is not null), async x =>
            {
                var host = await _database.Host()
                    .Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, x.Value.Id))
                    .FirstOrDefaultAsync(cancellationToken)
                    .ConfigureAwait(false);

                if (host is null) return;
                valid.Add(x.Value);
            });

            return valid;
        }
    }
}