public async Task RemoveClientLayerAsync(string clientId, string layerId)
        {
            await _myNoSqlWriter.TryDeleteAsync(AssetConditionNoSql.GeneratePartitionKey(clientId), AssetConditionNoSql.GenerateRowKey());

            await _assetConditionLayerLinkClientRepository.RemoveAsync(clientId, layerId);

            await _cacheManager.RemoveClientFromCacheAsync(clientId);
        }
        async Task <List <string> > IAvailableAssetClient.GetAssetIds(string clientId, bool isIosDevice)
        {
            try
            {
                var data = _readerAssetConditionNoSql.Get(
                    AssetConditionNoSql.GeneratePartitionKey(clientId),
                    AssetConditionNoSql.GenerateRowKey());

                if (data?.AssetConditions != null)
                {
                    return(data.AssetConditions.Where(o => o.AvailableToClient == true).Select(o => o.Asset).ToList());
                }
            }
            catch (Exception ex)
            {
                _log.Error(ex, $"Cannot read from MyNoSQL. Table: ${AssetConditionNoSql.TableName}, PK: {AssetConditionNoSql.GeneratePartitionKey(clientId)}, RK: {AssetConditionNoSql.GenerateRowKey()}");
                throw;
            }

            var result = await HttpClient.ClientGetAssetIdsAsync(clientId, isIosDevice);

            return(result.ToList());
        }
        public async Task <IEnumerable <IAssetCondition> > GetAssetConditionsByClient(string clientId)
        {
            var assetConditions = await _cacheManager.TryGetAssetConditionsForClientAsync(clientId);

            if (assetConditions != null)
            {
                return(assetConditions);
            }

            var assetDefaultLayer = await _cachedAssetConditionsService.GetDefaultLayerAsync();

            var defaultLayerConditions = await _cachedAssetConditionsService.GetConditionsAsync(assetDefaultLayer.Id);

            var map = new Dictionary <string, AssetCondition>();

            // Initialize asset conditions using default layer conditions
            foreach (var condition in defaultLayerConditions)
            {
                map[condition.Asset] = Mapper.Map <AssetCondition>(condition);
            }

            // Merge client conditions layers
            var layers = await GetLayersAsync(clientId);

            foreach (var layer in layers.OrderBy(e => e.Priority))
            {
                var explicitAssets = new HashSet <string>();

                var conditions = await _cachedAssetConditionsService.GetConditionsAsync(layer.Id);

                // Apply explicit assets conditions
                foreach (var condition in conditions)
                {
                    if (!map.TryGetValue(condition.Asset, out var value))
                    {
                        map[condition.Asset] = Mapper.Map <AssetCondition>(condition);
                    }
                    else
                    {
                        value.Apply(condition);
                    }

                    explicitAssets.Add(condition.Asset);
                }

                var defaultAssetCondition = await _cachedAssetConditionsService.GetDefaultConditionsAsync(layer.Id);

                if (defaultAssetCondition == null)
                {
                    continue;
                }

                // Apply implicit assets conditions
                var implicitAssets = map.Keys.Where(o => !explicitAssets.Contains(o));

                foreach (var asset in implicitAssets)
                {
                    map[asset].Apply(defaultAssetCondition);
                }
            }

            assetConditions = map.Values.Cast <IAssetCondition>().ToList();

            // Update asset conditions cache
            await _cacheManager.SaveAssetConditionsForClientAsync(clientId, assetConditions);

            await _myNoSqlWriter.TryInsertOrReplaceAsync(AssetConditionNoSql.Create(clientId, assetConditions));

            return(assetConditions);
        }