using AdsServingService.Domain.Exceptions;
using AdsServingService.Domain.SeedWork;

namespace AdsServingService.Domain.AggregatesModel.PacingAggregate;

/// <summary>
/// EN: Budget pacer - controls ad spend rate to last throughout the day.
/// VI: Budget pacer - điều khiển tốc độ chi tiêu quảng cáo để kéo dài cả ngày.
/// </summary>
public class BudgetPacer : Entity, IAggregateRoot
{
    private Guid _campaignId;
    private decimal _dailyBudget;
    private decimal _spentToday;
    private PacingStrategy _strategy;
    private DateTime _lastUpdated;

    public Guid CampaignId => _campaignId;
    public decimal DailyBudget => _dailyBudget;
    public decimal SpentToday => _spentToday;
    public PacingStrategy Strategy => _strategy;
    public DateTime LastUpdated => _lastUpdated;

    /// <summary>
    /// EN: Remaining budget for today.
    /// VI: Ngân sách còn lại trong ngày.
    /// </summary>
    public decimal RemainingBudget => _dailyBudget - _spentToday;

    /// <summary>
    /// EN: Budget utilization percentage.
    /// VI: Tỷ lệ phần trăm sử dụng ngân sách.
    /// </summary>
    public decimal UtilizationPercent => _dailyBudget > 0 ? (_spentToday / _dailyBudget) * 100 : 0;

    protected BudgetPacer() { }

    public BudgetPacer(Guid campaignId, decimal dailyBudget, PacingStrategy strategy)
    {
        if (dailyBudget <= 0)
            throw new AdsServingDomainException("Daily budget must be greater than zero");

        Id = Guid.NewGuid();
        _campaignId = campaignId;
        _dailyBudget = dailyBudget;
        _strategy = strategy;
        _spentToday = 0;
        _lastUpdated = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Check if campaign can serve an ad based on pacing strategy.
    /// VI: Kiểm tra xem chiến dịch có thể hiển thị quảng cáo dựa trên chiến lược pacing không.
    /// </summary>
    public bool CanServeAd(decimal estimatedCost)
    {
        if (_spentToday + estimatedCost > _dailyBudget)
            return false;

        if (_strategy == PacingStrategy.Smooth)
        {
            // Smooth pacing: slow down as budget depletes
            var remainingHoursInDay = (24 - DateTime.UtcNow.Hour);
            var hourlyBudget = _dailyBudget / 24;
            var allowedSpendThisHour = hourlyBudget * 1.2m; // 20% buffer

            return _spentToday + estimatedCost <= (DateTime.UtcNow.Hour * hourlyBudget + allowedSpendThisHour);
        }

        // Accelerated: spend as fast as possible
        return true;
    }

    /// <summary>
    /// EN: Record a spend transaction.
    /// VI: Ghi nhận một giao dịch chi tiêu.
    /// </summary>
    public void RecordSpend(decimal amount)
    {
        if (amount < 0)
            throw new AdsServingDomainException("Spend amount cannot be negative");

        _spentToday += amount;
        _lastUpdated = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Reset daily spend (called at start of new day).
    /// VI: Reset chi tiêu hàng ngày (gọi vào đầu ngày mới).
    /// </summary>
    public void ResetDailySpend()
    {
        _spentToday = 0;
        _lastUpdated = DateTime.UtcNow;
    }
}

/// <summary>
/// EN: Pacing strategy enumeration.
/// VI: Enum chiến lược pacing.
/// </summary>
public enum PacingStrategy
{
    /// <summary>
    /// EN: Smooth pacing - spread evenly throughout the day.
    /// VI: Pacing mượt - phân bổ đều trong ngày.
    /// </summary>
    Smooth = 1,

    /// <summary>
    /// EN: Accelerated - spend as fast as possible.
    /// VI: Tăng tốc - chi tiêu nhanh nhất có thể.
    /// </summary>
    Accelerated = 2
}
