using AdsManagerService.Domain.Exceptions;
using AdsManagerService.Domain.SeedWork;

#pragma warning disable CS0649 // Field is never assigned to (EF Core managed)

namespace AdsManagerService.Domain.AggregatesModel.AdSetAggregate;

/// <summary>
/// EN: Ad Set aggregate root - targeting and budget settings for a group of ads.
/// VI: Ad Set aggregate root - cài đặt targeting và ngân sách cho một nhóm quảng cáo.
/// </summary>
public class AdSet : Entity, IAggregateRoot
{
    private string _name = null!;
    private Guid _campaignId;
    private AdSetStatus _status = null!;
    private Targeting _targeting = null!;
    private BidStrategy _bidStrategy = null!;
    private decimal _dailyBudget;
    private DateTime? _startDate;
    private DateTime? _endDate;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    /// <summary>
    /// EN: Ad Set name.
    /// VI: Tên Ad Set.
    /// </summary>
    public string Name => _name;

    /// <summary>
    /// EN: Parent campaign ID.
    /// VI: ID chiến dịch cha.
    /// </summary>
    public Guid CampaignId => _campaignId;

    /// <summary>
    /// EN: Current status.
    /// VI: Trạng thái hiện tại.
    /// </summary>
    public AdSetStatus Status => _status;
    public int StatusId { get; private set; }

    /// <summary>
    /// EN: Targeting settings.
    /// VI: Cài đặt targeting.
    /// </summary>
    public Targeting Targeting => _targeting;

    /// <summary>
    /// EN: Bid strategy.
    /// VI: Chiến lược giá thầu.
    /// </summary>
    public BidStrategy BidStrategy => _bidStrategy;

    /// <summary>
    /// EN: Daily budget.
    /// VI: Ngân sách hàng ngày.
    /// </summary>
    public decimal DailyBudget => _dailyBudget;

    public DateTime? StartDate => _startDate;
    public DateTime? EndDate => _endDate;
    public DateTime CreatedAt => _createdAt;
    public DateTime? UpdatedAt => _updatedAt;

    protected AdSet() { }

    public AdSet(
        Guid campaignId,
        string name,
        Targeting targeting,
        BidStrategy bidStrategy,
        decimal dailyBudget) : this()
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new AdsDomainException("Ad Set name cannot be empty");
        if (dailyBudget <= 0)
            throw new AdsDomainException("Daily budget must be greater than zero");

        Id = Guid.NewGuid();
        _campaignId = campaignId;
        _name = name;
        _targeting = targeting;
        _bidStrategy = bidStrategy;
        _dailyBudget = dailyBudget;
        _status = AdSetStatus.Draft;
        StatusId = AdSetStatus.Draft.Id;
        _createdAt = DateTime.UtcNow;
    }

    public void Update(string name, decimal dailyBudget)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new AdsDomainException("Ad Set name cannot be empty");

        _name = name;
        _dailyBudget = dailyBudget;
        _updatedAt = DateTime.UtcNow;
    }

    public void SetTargeting(Targeting targeting)
    {
        _targeting = targeting ?? throw new AdsDomainException("Targeting cannot be null");
        _updatedAt = DateTime.UtcNow;
    }

    public void SetBidStrategy(BidStrategy bidStrategy)
    {
        _bidStrategy = bidStrategy ?? throw new AdsDomainException("Bid strategy cannot be null");
        _updatedAt = DateTime.UtcNow;
    }

    public void Activate()
    {
        if (_status != AdSetStatus.Draft && _status != AdSetStatus.Paused)
            throw new AdsDomainException("Only draft or paused ad sets can be activated");

        _status = AdSetStatus.Active;
        StatusId = AdSetStatus.Active.Id;
        _updatedAt = DateTime.UtcNow;
    }

    public void Pause()
    {
        if (_status != AdSetStatus.Active)
            throw new AdsDomainException("Only active ad sets can be paused");

        _status = AdSetStatus.Paused;
        StatusId = AdSetStatus.Paused.Id;
        _updatedAt = DateTime.UtcNow;
    }
}

/// <summary>
/// EN: Ad Set status enumeration.
/// VI: Enum trạng thái Ad Set.
/// </summary>
public class AdSetStatus : Enumeration
{
    public static readonly AdSetStatus Draft = new(1, nameof(Draft).ToLowerInvariant());
    public static readonly AdSetStatus Active = new(2, nameof(Active).ToLowerInvariant());
    public static readonly AdSetStatus Paused = new(3, nameof(Paused).ToLowerInvariant());
    public static readonly AdSetStatus Archived = new(4, nameof(Archived).ToLowerInvariant());

    public AdSetStatus(int id, string name) : base(id, name) { }

    public static IEnumerable<AdSetStatus> List() =>
        new[] { Draft, Active, Paused, Archived };
}
