using Valg.EVA.Skanning.Commands;
using Valg.EVA.Skanning.Commands.CreateCountingResult;
using Valg.EVA.Skanning.Commands.SetCountingLocked;
using System;
using Valg.EVA.Skanning.Contracts;
using Valg.EVA.Skanning.Diagnostics;
using Valg.EVA.Skanning.ServicesModel.ServiceContracts.CountResult.Write;

namespace Valg.EVA.Skanning.Services.CountResult
{
    public class CountingResultGenerator
    {
        private readonly ICommandDispatcher commandDispatcher;
        private readonly ITimingProbe timingProbe;
        private readonly IDatabaseConfiguration databaseConfiguration;

        public CountingResultGenerator(ICommandDispatcher commandDispatcher, ITimingProbe timingProbe, IDatabaseConfiguration databaseConfiguration)
        {
            this.commandDispatcher = commandDispatcher;
            this.timingProbe = timingProbe;
            this.databaseConfiguration = databaseConfiguration;
        }

        public GenerateCountingResultResult CreateResultForCounting(GenerateCountingResultParameters parameters)
        {
            var lockSucceeded = false;
            var generateSucceeded = false;
            var transferJobId = 0;
            Exception exception = null;

            try
            {
                timingProbe.Measure(() =>
                {
                    var lockCountingCommand = new SetCountingLockedCommand(parameters.CountingId, parameters.CountingConcurrencyToken, parameters.ExpectedBoxCountingsToLock, parameters.GeneratedBy);
                    var lockCountingResult = commandDispatcher.DispatchCommand<SetCountingLockedCommand, SetCountingLockedCommandResult>(lockCountingCommand);

                    if (!lockCountingResult.Failed)
                    {
                        lockSucceeded = true;

                        var createCountingResultCommand = new CreateCountingResultCommand(parameters.CountingId, lockCountingResult.UpdatedConcurrencyToken,
                            lockCountingResult.ExpectedBoxCountingsToCreateResultFor, parameters.GeneratedBy, parameters.ReportingUnitIdentifier, parameters.IsInEmergencyMode);

                        var createCountingResult = commandDispatcher.DispatchCommand<CreateCountingResultCommand, CreateCountingResultCommandResult>(createCountingResultCommand);
                        transferJobId = createCountingResult.TransferJobId;
                        generateSucceeded = !createCountingResult.Failed;
                    }
                }, () => new DefaultMeasurementEventData(parameters.ReportingUnitIdentifier, 
                            (int) ServicesInstrumentedEvents.GenerateCountingResult, 
                            ServicesInstrumentedEvents.GenerateCountingResult.ToString(),
                            databaseConfiguration.DatabaseServerName));
            }
            catch (Exception ex)
            {
                exception = ex;
                EvaSkanningEventSource.Log.GenerateCountingResultFailed(ex.ToString());
            }

            return new GenerateCountingResultResult(transferJobId, lockSucceeded, generateSucceeded, exception);
        }
    }
}
