using Valg.EVA.Skanning.Contracts.CommonEnums;
using Valg.EVA.Skanning.Entity.SqlConnection;
using Valg.EVA.Skanning.Entity.WriteModel;
using Valg.EVA.Skanning.Repositories.Counting;
using Valg.EVA.Skanning.ServicesModel.Internal;

namespace Valg.EVA.Skanning.Commands.RegisterBox
{
    public class RegisterBoxForCountingCommandHandler : IHandleCommandsWithReturnValue<RegisterBoxForCountingCommand, RegisterBoxForCountingCommandResult>
    {
        private readonly ICountingRepository countingRepository;
        private readonly ICountingWriteableRepository countingWriteableRepository;
        private readonly TransactionScopeFactory transactionScopeFactory;
        private readonly CountingUniqueIdCreator countingUniqueIdCreator;

        public RegisterBoxForCountingCommandHandler(ICountingRepository countingRepository, ICountingWriteableRepository countingWriteableRepository, TransactionScopeFactory transactionScopeFactory, CountingUniqueIdCreator countingUniqueIdCreator)
        {
            this.countingRepository = countingRepository;
            this.countingWriteableRepository = countingWriteableRepository;
            this.transactionScopeFactory = transactionScopeFactory;
            this.countingUniqueIdCreator = countingUniqueIdCreator;
        }

        public void HandleCommand(RegisterBoxForCountingCommand command)
        {
            var result = new RegisterBoxForCountingCommandResult();
            CommandResult = result;

            using (var scope = transactionScopeFactory.GetTransactionScope())
            {
                var uniqueId = countingUniqueIdCreator.Create(command.BarcodeLong, command.BarcodeShort);
                var activeCounting = countingRepository.GetActiveCounting(uniqueId, command.CountingEmlAreaContextId, null);
                if (activeCounting != null)
                {
                    if (!activeCounting.HasBoxesRegistered)
                    {
                        RegisterAllBoxesForCounting(command.BarcodeLong, command.BarcodeShort, activeCounting.Id);
                    }

                    if (command.IsInEmergencyMode)
                    {
                        countingWriteableRepository.MarkCountingAsProcessedDuringEmergencMode(activeCounting.Id);
                    }

                    var boxCounting = countingRepository.GetBoxCounting(command.BarcodeLong, command.BarcodeShort, activeCounting.Id);

                    if (boxCounting != null)
                    {
                        var stateIsRegisteredNotScanned = boxCounting.State == BoxCountingState.RegisteredNotScanned;
                        var stateIsReadyForScan = boxCounting.State == BoxCountingState.ReadyForScan;

                        if (stateIsRegisteredNotScanned || stateIsReadyForScan)
                        {
                            if (stateIsRegisteredNotScanned)
                            {
                                countingWriteableRepository.UpdateBoxCountingState(
                                    command.BarcodeLong,
                                    command.BarcodeShort,
                                    activeCounting.Id,
                                    BoxCountingState.ReadyForScan,
                                    boxCounting.Modified,
                                    BoxCountingState.RegisteredNotScanned,
                                    command.ChangedBy);
                            }

                            result.BoxIsReadyForScan = true;
                            result.BoxCountingId = boxCounting.Id;
                            result.BarcodeLong = boxCounting.BarcodeLong;
                            result.BarcodeShort = boxCounting.BarcodeShort;
                            result.CountingId = boxCounting.CountingId;
                        }
                    }
                }
                scope.Complete();
            }
        }

        private void RegisterAllBoxesForCounting(string barcodeLong, string barcodeShort, int countingId)
        {
            var totalNumberOfBoxes = barcodeLong.GetTotalBoxCountFromBarcodeLong();
            for (int i = 0; i < totalNumberOfBoxes; i++)
            {
                var newBarcode = barcodeLong.Substring(0, BarcodeSplitter.BoxNumberStartIndex)
                                 + (i + 1).ToString("D2")
                                 + totalNumberOfBoxes.ToString("D2")
                                 + barcodeLong.Substring(BarcodeSplitter.ContentTypeStartIndex);

                var boxCountingInsert = new BoxCountingInsert
                {
                    State = BoxCountingState.RegisteredNotScanned,
                    BarcodeLong = newBarcode,
                    BarcodeShort = barcodeShort,
                    CountingId = countingId
                };

                countingWriteableRepository.InsertBoxCounting(boxCountingInsert);
            }
        }

        public RegisterBoxForCountingCommandResult CommandResult { get; private set; }
    }
}
