using System;
using System.Linq;
using System.Threading.Tasks;
using Valg.EVA.Skanning.Entity.ReadModel;
using Valg.EVA.Skanning.Commands;
using Valg.EVA.Skanning.Commands.SetTransferFailed;
using Valg.EVA.Skanning.Contracts;
using Valg.EVA.Skanning.Diagnostics;
using Valg.EVA.Skanning.Repositories.Transfers;
using Valg.EVA.Skanning.ServicesModel.ServiceContracts.TransferCounting.Write;

namespace Valg.EVA.Skanning.BackgroundServices.CleanupAbandonedTransfers
{
    public class CleanupAbandonedTransfersService
    {
        private readonly ITransferRepository transferRepository;
        private readonly ICommandDispatcher commandDispatcher;
        private readonly ISendTimeoutFromServiceBindingUtility sendTimeoutFromServiceBinding;
        private readonly IExternalEndpointsConfiguration externalEndpointsConfiguration;

        public CleanupAbandonedTransfersService(ITransferRepository transferRepository, ICommandDispatcher commandDispatcher, 
            ISendTimeoutFromServiceBindingUtility sendTimeoutFromServiceBinding, IExternalEndpointsConfiguration externalEndpointsConfiguration)
        {
            this.transferRepository = transferRepository;
            this.commandDispatcher = commandDispatcher;
            this.sendTimeoutFromServiceBinding = sendTimeoutFromServiceBinding;
            this.externalEndpointsConfiguration = externalEndpointsConfiguration;
        }

        public async Task ExecuteAsync()
        {
            var timeout = sendTimeoutFromServiceBinding.Get();

            if (timeout != -1)
            {
                var transfersEligibleForCleanup = await transferRepository.GetTransfersEligibleForCleanupAsync(timeout).ConfigureAwait(false);
                var tasks = transfersEligibleForCleanup.Select(t => SetTransferInFailedState(t, timeout));

                await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false);
            }
        }

        private async Task SetTransferInFailedState(TransferToCleanUp transferToCleanUp, int timeout)
        {
            try
            {
                EvaSkanningEventSource.Log.TransferIsAbandonedAndEligibleForCleanup(transferToCleanUp.TransferId, timeout, externalEndpointsConfiguration.TransferWebServiceUrl);
                await commandDispatcher.DispatchCommandAsync(new SetTransferFailedCommand(transferToCleanUp.TransferId, TransferCountingFailureDetails.timeoutError, "CleanupAbandonedTransfersService", transferToCleanUp.LastUpdated)).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                EvaSkanningEventSource.Log.ErrorWhileAttemptingToSetTransferInFailedState(transferToCleanUp.TransferId, e.ToString());
            }
        }
    }
}
