public async Task <ProviderReferenceData> GetProviderReferenceDataAsync(CancellationToken cancellationToken, long ukprn)
        {
            try
            {
                using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
                {
                    var data = await context.FundingClaimsProviderReferenceData.FirstOrDefaultAsync(x =>
                                                                                                    x.Ukprn == ukprn, cancellationToken);

                    if (data != null)
                    {
                        return(new ProviderReferenceData()
                        {
                            AebcClallocation = data.AebcClallocation,
                            EditAccess = data.EditAccess,
                        });
                    }
                    else
                    {
                        return(new ProviderReferenceData());
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError($"Failed to get GetProviderRefernceDataAsync for ukprn : {ukprn}", e);
                throw;
            }
        }
        public async Task <CollectionDetail> GetLatestCollectionDetailAsync(int collectionYear, CancellationToken cancellationToken)
        {
            try
            {
                _logger.LogInfo($"return GetLatestCollectionDetailAsync : {collectionYear}");

                using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
                {
                    return(await context.CollectionDetail.Where(x => x.CollectionYear == collectionYear)
                           .OrderByDescending(x => x.SubmissionCloseDateUtc)
                           .Select(x => new CollectionDetail()
                    {
                        CollectionId = x.CollectionId,
                        CollectionName = x.CollectionName,
                        DisplayTitle = x.DisplayTitle,
                        SubmissionCloseDateUtc = x.SubmissionCloseDateUtc,
                        CollectionCode = x.CollectionCode
                    })
                           .FirstOrDefaultAsync(cancellationToken));
                }
            }
            catch (Exception e)
            {
                _logger.LogError($"error GetLatestCollectionDetailAsync : {collectionYear}", e);
                throw;
            }
        }
        public async Task <int> GetLatestSubmissionVersionAsync(CancellationToken cancellationToken, long ukprn)
        {
            using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
            {
                var latestSubmission = await context.Submission
                                       .Where(x => x.Ukprn == ukprn && x.IsSubmitted)
                                       .MaxAsync(x => (int?)x.Version, cancellationToken);

                return(latestSubmission.GetValueOrDefault() + 1);
            }
        }
        public async Task <string> ConvertToSubmissionAsync(CancellationToken cancellationToken, long ukprn, string collectionName)
        {
            using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
            {
                var submission = await GetSubmissionAsync(cancellationToken, context, ukprn, null, collectionName);

                if (submission == null)
                {
                    throw new ArgumentException($"no submission found for submission for ukprn : {ukprn}, collection Name : {collectionName}, can not proceed with submission");
                }

                var contractsAllocations =
                    await _fundingClaimsReferenceDataService.GetContractAllocationsAsync(
                        cancellationToken,
                        submission.Ukprn,
                        submission.Collection.CollectionYear);

                var fundingStreamPeriodCodes = context.SubmissionValue
                                               .Where(x => x.SubmissionId == submission.SubmissionId)
                                               .Select(x => x.FundingStreamPeriodCode)
                                               .Distinct();

                foreach (var value in fundingStreamPeriodCodes)
                {
                    var contract = contractsAllocations?.FirstOrDefault(x => x.FundingStreamPeriodCode.Equals(value));

                    if (contract != null)
                    {
                        submission.OrganisationIdentifier = contract.OrganisationIdentifier;

                        submission.SubmissionContractDetail.Add(new SubmissionContractDetail()
                        {
                            SubmissionId            = submission.SubmissionId,
                            FundingStreamPeriodCode = value,
                            ContractValue           = contract.MaximumContractValue,
                        });
                    }
                }

                // Mark as submitted
                submission.IsSubmitted          = true;
                submission.SubmittedBy          = submission.CreatedBy;
                submission.SubmittedDateTimeUtc = _dateTimeProvider.GetNowUtc();
                submission.Declaration          = true;
                submission.Version = await GetLatestSubmissionVersionAsync(cancellationToken, ukprn);

                await context.SaveChangesAsync(cancellationToken);

                _logger.LogInfo($"Successfully converted to funding claims submission for submission Id :{submission.SubmissionId}");

                return(submission.SubmissionId.ToString());
            }
        }
        public async Task <FundingClaimsData> GetSubmissionDetailsAsync(CancellationToken cancellationToken, long ukprn, Guid?submissionId = null, string collectionName = null)
        {
            var result = new FundingClaimsData();
            var items  = new List <FundingClaimsDataItem>();

            try
            {
                using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
                {
                    var submission = await GetSubmissionAsync(cancellationToken, context, ukprn, submissionId, collectionName);

                    if (submission == null)
                    {
                        _logger.LogDebug($"submission not found for submission id : {submissionId} and ukprn : {ukprn}");
                        return(result);
                    }

                    result.CovidDeclaration = submission.CovidDeclaration;

                    items = await context.SubmissionValue.Where(x => x.SubmissionId == submission.SubmissionId)
                            .Select(x => new FundingClaimsDataItem()
                    {
                        ContractAllocationNumber = x.ContractAllocationNumber,
                        DeliverableCode          = x.FundingStreamPeriodDeliverableCode.DeliverableCode,
                        DeliverableDescription   = x.FundingStreamPeriodDeliverableCode.Description,
                        DeliveryToDate           = x.DeliveryToDate,
                        ExceptionalAdjustments   = x.ExceptionalAdjustments,
                        ForecastedDelivery       = x.ForecastedDelivery,
                        FundingStreamPeriodCode  = x.FundingStreamPeriodCode,
                        StudentNumbers           = x.StudentNumbers,
                        TotalDelivery            = x.TotalDelivery,
                    })
                            .ToListAsync(cancellationToken);

                    result.FundingClaimsDataItems = items;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(
                    $"error getting submission detail for ukprn : {ukprn}, submission id : {submissionId} ", e);
                throw;
            }

            _logger.LogInfo($"return submission detail for ukprn : {ukprn}, submission id : {submissionId}");

            return(result);
        }
        public async Task UpdateCovidDeclaration(CancellationToken cancellationToken, long ukprn, string collectionName, bool?value)
        {
            using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
            {
                var submission = await GetSubmissionAsync(cancellationToken, context, ukprn, null, collectionName, false);

                if (submission == null)
                {
                    throw new ArgumentException(
                              $"no submission found for submission for ukprn : {ukprn}, collection Name : {collectionName}, can not proceed with submission");
                }

                submission.CovidDeclaration = value;

                await context.SaveChangesAsync(cancellationToken);
            }
        }
        public async Task <bool> SaveSubmissionAsync(CancellationToken cancellationToken, FundingClaimsData fundingClaimsData)
        {
            try
            {
                using (IFundingClaimsDataContext context = _fundingClaimsContextFactory())
                {
                    var today = _dateTimeProvider.GetNowUtc();

                    var submission = await GetSubmissionAsync(cancellationToken, context, fundingClaimsData.Ukprn, null, fundingClaimsData.CollectionName, false);

                    //find unique FSPs
                    var fundingStreamPeriodCodes = fundingClaimsData.FundingClaimsDataItems
                                                   .Select(x => x.FundingStreamPeriodCode).Distinct();

                    var deliverableCodes = await context.FundingStreamPeriodDeliverableCode.ToListAsync(cancellationToken);

                    if (submission == null)
                    {
                        submission = new Submission
                        {
                            SubmissionId       = Guid.NewGuid(),
                            Ukprn              = fundingClaimsData.Ukprn,
                            Collection         = await context.CollectionDetail.SingleOrDefaultAsync(x => x.CollectionName == fundingClaimsData.CollectionName, cancellationToken),
                            CreatedBy          = fundingClaimsData.UserName,
                            CreatedDateTimeUtc = today,
                        };

                        var latestSubmission = await GetSubmissionAsync(cancellationToken, context, fundingClaimsData.Ukprn, null, fundingClaimsData.CollectionName, true);

                        if (latestSubmission != null & fundingStreamPeriodCodes.All(x => x != _fundingStreamPeriodCodes[fundingClaimsData.CollectionYear].Ilr16To19))
                        {
                            submission.SubmissionValue = context.SubmissionValue.Where(x => x.SubmissionId == latestSubmission.SubmissionId &&
                                                                                       x.FundingStreamPeriodCode == _fundingStreamPeriodCodes[fundingClaimsData.CollectionYear].Ilr16To19)
                                                         .ToList();
                        }

                        context.Submission.Add(submission);
                    }
                    else
                    {
                        //find and remove values
                        context.SubmissionValue.RemoveRange(context.SubmissionValue.Where(x =>
                                                                                          x.SubmissionId == submission.SubmissionId &&
                                                                                          fundingStreamPeriodCodes.Contains(x.FundingStreamPeriodCode)));
                        context.ChangeLog.RemoveRange(
                            context.ChangeLog.Where(f => f.SubmissionId == submission.SubmissionId));

                        _logger.LogInfo(
                            $"removed funding claims draft data submission detail for ukprn : {fundingClaimsData.Ukprn}, collectionName: {fundingClaimsData.CollectionName}");
                    }

                    submission.IsSigned             = false;
                    submission.SubmittedDateTimeUtc = null;
                    submission.SubmittedBy          = null;
                    submission.SignedOnDateTimeUtc  = null;
                    submission.Version = 0;

                    foreach (var value in fundingClaimsData.FundingClaimsDataItems)
                    {
                        var deliverableCode = deliverableCodes.Single(x => x.DeliverableCode == value.DeliverableCode && x.FundingStreamPeriodCode == value.FundingStreamPeriodCode);

                        submission.SubmissionValue.Add(new SubmissionValue()
                        {
                            SubmissionId                       = submission.SubmissionId,
                            ContractAllocationNumber           = value.ContractAllocationNumber,
                            ExceptionalAdjustments             = value.ExceptionalAdjustments.GetValueOrDefault(),
                            FundingStreamPeriodCode            = value.FundingStreamPeriodCode,
                            ForecastedDelivery                 = value.ForecastedDelivery.GetValueOrDefault(),
                            DeliveryToDate                     = value.DeliveryToDate.GetValueOrDefault(),
                            StudentNumbers                     = value.StudentNumbers.GetValueOrDefault(),
                            TotalDelivery                      = value.TotalDelivery.GetValueOrDefault(),
                            FundingStreamPeriodDeliverableCode = deliverableCode,
                        });
                    }

                    submission.ChangeLog = new List <ChangeLog>
                    {
                        new ChangeLog
                        {
                            SubmissionId       = submission.SubmissionId,
                            UserEmailAddress   = fundingClaimsData.EmailAddress,
                            UpdatedDateTimeUtc = today,
                        },
                    };

                    await context.SaveChangesAsync(cancellationToken);

                    _logger.LogInfo(
                        $"saved funding claims draft data submission for ukprn : {fundingClaimsData.Ukprn}, collectionPerioId : {fundingClaimsData.CollectionName} ");
                }
            }
            catch (Exception e)
            {
                _logger.LogError(
                    $"error getting submission detail for ukprn : {fundingClaimsData.Ukprn}, collectionPerioId id : {fundingClaimsData.CollectionName} ",
                    e);
                throw;
            }

            return(true);
        }
        private async Task <Submission> GetSubmissionAsync(CancellationToken cancellationToken, IFundingClaimsDataContext context, long ukprn, Guid?submissionId = null, string collectionName = null, bool?isSubmitted = null)
        {
            var query = context.Submission.Include(x => x.Collection)
                        .Where(x => x.Ukprn == ukprn);

            if (!string.IsNullOrEmpty(collectionName))
            {
                query = query.Where(x => x.Collection.CollectionName == collectionName);
            }

            if (submissionId != null)
            {
                query = query.Where(x => x.SubmissionId == submissionId);
            }

            if (isSubmitted != null)
            {
                query = query.Where(x => x.IsSubmitted == isSubmitted);
            }

            return(await query.OrderByDescending(x => x.CreatedDateTimeUtc).FirstOrDefaultAsync(cancellationToken));
        }