public void GetCurrencyExchangeRatesAsync_GetsExchangeRatesForWorkDays()
        {
            //Arrange
            var dateFrom     = DateTime.Parse("2020-05-11"); //Monday
            var dateTo       = DateTime.Parse("2020-05-15"); //Friday
            var currencyFrom = "USD";
            var currencyTo   = "EUR";

            //Act
            var result = _currencyRatesRetriver.GetCurrencyExchangeRatesAsync(currencyFrom, currencyTo, dateFrom, dateTo).Result;

            //Assert
            Assert.AreEqual(5, result.Count);
            Assert.IsTrue(result.TrueForAll(x => x.Value > 0));
            for (int i = 0; i < 5; i++)
            {
                Assert.IsTrue(result.Any(x => x.Date == dateFrom.AddDays(i)));
            }
        }
        public async Task <List <CurrencyExchangeRate> > GetCurrencyExchangeRatesAsync(Dictionary <string, string> currencyCodes, DateTime from, DateTime to)
        {
            var result = new List <CurrencyExchangeRate>();

            foreach (var currencyCode in currencyCodes)
            {
                List <CurrencyExchangeRate> currencyRates;

                //chceck if data is available in db otherwise ask external api
                if (await _currencyRepository.IsDataAvailable(currencyCode.Key, currencyCode.Value, from, to))
                {
                    currencyRates = await _currencyRepository.GetAsync(currencyCode.Key, currencyCode.Value, from, to);
                }
                else
                {
                    currencyRates = await _currencyRatesRetriver.GetCurrencyExchangeRatesAsync(currencyCode.Key, currencyCode.Value, from, to);

                    //resolve missing days
                    var requiredDates = Enumerable.Range(0, 1 + to.Subtract(from).Days)
                                        .Select(offset => from.AddDays(offset))
                                        .ToArray();

                    var missingDates = requiredDates.Where(x => !currencyRates.Any(y => y.Date == x));
                    foreach (var missingDate in missingDates.OrderBy(x => x.Date))
                    {
                        var previousRate = currencyRates.FirstOrDefault(x => x.Date == missingDate.Date.AddDays(-1));
                        if (previousRate != null)
                        {
                            currencyRates.Add(new CurrencyExchangeRate()
                            {
                                CurrencyFrom      = previousRate.CurrencyFrom,
                                CurrrencyTo       = previousRate.CurrrencyTo,
                                Date              = missingDate,
                                Value             = previousRate.Value,
                                IsFromPreviousDay = true
                            });
                        }
                        else
                        {
                            var offset    = 30;
                            var pastRates = await _currencyRatesRetriver.GetCurrencyExchangeRatesAsync(currencyCode.Key, currencyCode.Value, missingDate.Date.AddDays(-1 * offset), missingDate);

                            for (int i = 1; i < offset; i++)
                            {
                                var found = pastRates.FirstOrDefault(x => x.Date == missingDate.AddDays(-1 * i));
                                if (found != null)
                                {
                                    found.IsFromPreviousDay = true;
                                    found.Date = missingDate;
                                    currencyRates.Add(found);
                                    break;
                                }
                            }
                        }
                    }
                    await _currencyRepository.StoreAsync(currencyRates);
                }
                result.AddRange(currencyRates.OrderBy(x => x.Date));
            }
            return(result);
        }