using BankSampahApp.Models;

namespace BankSampahApp.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
        };
    }
}