using MiningService.Domain.SeedWork;

namespace MiningService.Domain.AggregatesModel.ConfigurationAggregate;

/// <summary>
/// EN: Streak Configuration - controls streak bonus tiers.
/// VI: Cấu hình Streak - điều khiển các cấp thưởng streak.
/// </summary>
public class StreakConfiguration : Entity, IAggregateRoot
{
    public const string ConfigKey = "streak";

    private readonly List<StreakTier> _tiers = new();

    /// <summary>
    /// EN: Streak bonus tiers.
    /// VI: Các cấp thưởng streak.
    /// </summary>
    public IReadOnlyCollection<StreakTier> Tiers => _tiers.AsReadOnly();

    /// <summary>
    /// EN: Whether grace period is enabled.
    /// VI: Thời gian ân hạn có được bật không.
    /// </summary>
    public bool GracePeriodEnabled { get; private set; }

    /// <summary>
    /// EN: Grace period in hours.
    /// VI: Thời gian ân hạn tính bằng giờ.
    /// </summary>
    public int GracePeriodHours { get; private set; }

    /// <summary>
    /// EN: Cost in MP to recover lost streak.
    /// VI: Chi phí MP để khôi phục streak đã mất.
    /// </summary>
    public decimal RecoveryCost { get; private set; }

    /// <summary>
    /// EN: Days of streak to earn one freeze token.
    /// VI: Số ngày streak để kiếm một token đóng băng.
    /// </summary>
    public int FreezeTokenDays { get; private set; }

    public DateTime UpdatedAt { get; private set; }
    public Guid UpdatedBy { get; private set; }

    private StreakConfiguration() { }

    public static StreakConfiguration CreateDefault()
    {
        var config = new StreakConfiguration
        {
            Id = Guid.NewGuid(),
            GracePeriodEnabled = true,
            GracePeriodHours = 24,
            RecoveryCost = 50m,
            FreezeTokenDays = 7,
            UpdatedAt = DateTime.UtcNow,
            UpdatedBy = Guid.Empty
        };

        config._tiers.AddRange(new[]
        {
            new StreakTier(1, 2, 0m, null, 0),
            new StreakTier(3, 6, 0.10m, "3-day badge", 0),
            new StreakTier(7, 13, 0.25m, "7-day badge", 50),
            new StreakTier(14, 29, 0.50m, "14-day badge", 100),
            new StreakTier(30, 59, 1.0m, "30-day badge", 300),
            new StreakTier(60, 89, 1.25m, "60-day badge", 500),
            new StreakTier(90, int.MaxValue, 1.50m, "90-day badge", 1000)
        });

        return config;
    }

    public void Update(int? gracePeriodHours, decimal? recoveryCost, int? freezeTokenDays, Guid updatedBy)
    {
        if (gracePeriodHours.HasValue && gracePeriodHours.Value > 0)
            GracePeriodHours = gracePeriodHours.Value;
        if (recoveryCost.HasValue && recoveryCost.Value >= 0)
            RecoveryCost = recoveryCost.Value;
        if (freezeTokenDays.HasValue && freezeTokenDays.Value > 0)
            FreezeTokenDays = freezeTokenDays.Value;

        UpdatedAt = DateTime.UtcNow;
        UpdatedBy = updatedBy;
    }

    public void UpdateTiers(List<StreakTier> tiers, Guid updatedBy)
    {
        _tiers.Clear();
        _tiers.AddRange(tiers);
        UpdatedAt = DateTime.UtcNow;
        UpdatedBy = updatedBy;
    }
}

/// <summary>
/// EN: Streak tier value object.
/// VI: Value object cấp streak.
/// </summary>
public record StreakTier(
    int MinDays,
    int MaxDays,
    decimal BonusPercent,
    string? BadgeName,
    decimal MilestoneMpBonus);
