189 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C#
		
	
	
using BpsRwApp.Models;
 | 
						|
 | 
						|
namespace BpsRwApp.Services;
 | 
						|
 | 
						|
/// <summary>
 | 
						|
/// Service implementation untuk menangani statistik aplikasi
 | 
						|
/// Menggunakan base service untuk common functionality
 | 
						|
/// </summary>
 | 
						|
public class StatisticsService : BaseService, IStatisticsService
 | 
						|
{
 | 
						|
    private readonly ICacheService _cacheService;
 | 
						|
    private readonly IAppConfigurationService _appConfig;
 | 
						|
    private readonly IValidationService _validationService;
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Cache key untuk statistik
 | 
						|
    /// </summary>
 | 
						|
    private const string StatisticsCacheKey = "current_statistics";
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Constructor dengan dependency injection
 | 
						|
    /// </summary>
 | 
						|
    /// <param name="logger">Logger untuk logging</param>
 | 
						|
    /// <param name="cache">Memory cache untuk caching</param>
 | 
						|
    /// <param name="configuration">Configuration untuk settings</param>
 | 
						|
    /// <param name="cacheService">Cache service</param>
 | 
						|
    /// <param name="appConfig">Application configuration service</param>
 | 
						|
    /// <param name="validationService">Validation service</param>
 | 
						|
    public StatisticsService(
 | 
						|
        ILogger<StatisticsService> logger,
 | 
						|
        Microsoft.Extensions.Caching.Memory.IMemoryCache cache,
 | 
						|
        IConfiguration configuration,
 | 
						|
        ICacheService cacheService,
 | 
						|
        IAppConfigurationService appConfig,
 | 
						|
        IValidationService validationService) : base(logger, cache, configuration)
 | 
						|
    {
 | 
						|
        _cacheService = cacheService ?? throw new ArgumentNullException(nameof(cacheService));
 | 
						|
        _appConfig = appConfig ?? throw new ArgumentNullException(nameof(appConfig));
 | 
						|
        _validationService = validationService ?? throw new ArgumentNullException(nameof(validationService));
 | 
						|
    }
 | 
						|
 | 
						|
    /// <inheritdoc/>
 | 
						|
    public async Task<StatisticsModel> GetCurrentStatisticsAsync()
 | 
						|
    {
 | 
						|
        return await ExecuteWithErrorHandlingAsync(
 | 
						|
            async () => await _cacheService.GetOrSetWithSlidingAsync(
 | 
						|
                StatisticsCacheKey,
 | 
						|
                LoadStatisticsFromSourceAsync,
 | 
						|
                _appConfig.CacheSettings.StatisticsSlidingExpiration,
 | 
						|
                _appConfig.CacheSettings.StatisticsExpiration,
 | 
						|
                Microsoft.Extensions.Caching.Memory.CacheItemPriority.High),
 | 
						|
            "Fetching current statistics",
 | 
						|
            GetDefaultStatistics());
 | 
						|
    }
 | 
						|
 | 
						|
    /// <inheritdoc/>
 | 
						|
    public async Task<StatisticsModel> GetStatisticsByPeriodAsync(DateTime startDate, DateTime endDate)
 | 
						|
    {
 | 
						|
        return await ExecuteWithErrorHandlingAsync(
 | 
						|
            async () =>
 | 
						|
            {
 | 
						|
                var validation = _validationService.ValidateDateRange(startDate, endDate);
 | 
						|
                if (!validation.IsValid)
 | 
						|
                {
 | 
						|
                    throw new ArgumentException(string.Join("; ", validation.Errors));
 | 
						|
                }
 | 
						|
 | 
						|
                return await LoadStatisticsByPeriodFromSourceAsync(startDate, endDate);
 | 
						|
            },
 | 
						|
            $"Fetching statistics for period {startDate:yyyy-MM-dd} to {endDate:yyyy-MM-dd}");
 | 
						|
    }
 | 
						|
 | 
						|
    /// <inheritdoc/>
 | 
						|
    public async Task<bool> UpdateStatisticsAsync(StatisticsModel statistics)
 | 
						|
    {
 | 
						|
        return await ExecuteWithErrorHandlingAsync(
 | 
						|
            async () =>
 | 
						|
            {
 | 
						|
                ArgumentNullException.ThrowIfNull(statistics);
 | 
						|
 | 
						|
                var validation = _validationService.ValidateStatistics(statistics);
 | 
						|
                if (!validation.IsValid)
 | 
						|
                {
 | 
						|
                    _logger.LogWarning("Invalid statistics data: {Errors}", string.Join("; ", validation.Errors));
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
 | 
						|
                // Simulate async update operation
 | 
						|
                if (_appConfig.DevelopmentSettings.SimulatedDelayMs > 0)
 | 
						|
                {
 | 
						|
                    await Task.Delay(_appConfig.DevelopmentSettings.SimulatedDelayMs);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    await Task.Delay(10);
 | 
						|
                }
 | 
						|
 | 
						|
                // Clear cache after update
 | 
						|
                _cacheService.Remove(StatisticsCacheKey);
 | 
						|
 | 
						|
                return true;
 | 
						|
            },
 | 
						|
            "Updating statistics",
 | 
						|
            false);
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Load statistics from data source (placeholder for actual implementation)
 | 
						|
    /// </summary>
 | 
						|
    /// <returns>Current statistics</returns>
 | 
						|
    private async Task<StatisticsModel> LoadStatisticsFromSourceAsync()
 | 
						|
    {
 | 
						|
        // In a real application, this would load from database, API, etc.
 | 
						|
        await Task.CompletedTask;
 | 
						|
 | 
						|
        // Get base values from configuration
 | 
						|
        var baseUsers = _appConfig.StatisticsSettings.BaseUsers;
 | 
						|
        var baseWaste = _appConfig.StatisticsSettings.BaseWaste;
 | 
						|
 | 
						|
        // Simulate some growth over time
 | 
						|
        var daysSinceStart = (DateTime.UtcNow - new DateTime(2024, 1, 1)).Days;
 | 
						|
        var growthFactor = Math.Min(_appConfig.StatisticsSettings.MaxGrowthFactor,
 | 
						|
            1.0 + (daysSinceStart * _appConfig.StatisticsSettings.GrowthFactorMultiplier));
 | 
						|
 | 
						|
        return new StatisticsModel
 | 
						|
        {
 | 
						|
            TotalUsers = (int)(baseUsers * growthFactor),
 | 
						|
            WasteCollected = baseWaste * (decimal)growthFactor,
 | 
						|
            RewardsDistributed = (int)(_appConfig.StatisticsSettings.BaseRewards * growthFactor),
 | 
						|
            EnvironmentImpact = Math.Min(99.9m, _appConfig.StatisticsSettings.BaseEnvironmentImpact + (decimal)(growthFactor * 2))
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Load statistics for specific period (placeholder)
 | 
						|
    /// </summary>
 | 
						|
    /// <param name="startDate">Start date</param>
 | 
						|
    /// <param name="endDate">End date</param>
 | 
						|
    /// <returns>Period statistics</returns>
 | 
						|
    private async Task<StatisticsModel> LoadStatisticsByPeriodFromSourceAsync(DateTime startDate, DateTime endDate)
 | 
						|
    {
 | 
						|
        await Task.CompletedTask;
 | 
						|
 | 
						|
        // Calculate period-specific statistics
 | 
						|
        var days = (endDate - startDate).Days + 1;
 | 
						|
        var dailyAverage = await GetDailyAverageAsync();
 | 
						|
 | 
						|
        return new StatisticsModel
 | 
						|
        {
 | 
						|
            TotalUsers = dailyAverage.TotalUsers * days / 365,
 | 
						|
            WasteCollected = dailyAverage.WasteCollected * days,
 | 
						|
            RewardsDistributed = dailyAverage.RewardsDistributed * days,
 | 
						|
            EnvironmentImpact = dailyAverage.EnvironmentImpact
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Get daily average statistics
 | 
						|
    /// </summary>
 | 
						|
    /// <returns>Daily average statistics</returns>
 | 
						|
    private async Task<StatisticsModel> GetDailyAverageAsync()
 | 
						|
    {
 | 
						|
        await Task.CompletedTask;
 | 
						|
 | 
						|
        return new StatisticsModel
 | 
						|
        {
 | 
						|
            TotalUsers = 3, // New users per day
 | 
						|
            WasteCollected = 0.1m, // Tons per day
 | 
						|
            RewardsDistributed = 5, // Rewards per day
 | 
						|
            EnvironmentImpact = 98.5m // Overall impact
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    /// Get default statistics when error occurs
 | 
						|
    /// </summary>
 | 
						|
    /// <returns>Default statistics</returns>
 | 
						|
    private StatisticsModel GetDefaultStatistics()
 | 
						|
    {
 | 
						|
        return new StatisticsModel
 | 
						|
        {
 | 
						|
            TotalUsers = _appConfig.StatisticsSettings.BaseUsers,
 | 
						|
            WasteCollected = _appConfig.StatisticsSettings.BaseWaste,
 | 
						|
            RewardsDistributed = _appConfig.StatisticsSettings.BaseRewards,
 | 
						|
            EnvironmentImpact = _appConfig.StatisticsSettings.BaseEnvironmentImpact
 | 
						|
        };
 | 
						|
    }
 | 
						|
} |