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

namespace AdsManagerService.Domain.AggregatesModel.AudienceAggregate;

/// <summary>
/// EN: Custom Audience aggregate root - uploaded lists or website visitors.
/// VI: Custom Audience aggregate root - danh sách upload hoặc khách truy cập website.
/// </summary>
public class CustomAudience : Entity, IAggregateRoot
{
    private string _name = null!;
    private Guid _advertiserId;
    private AudienceSource _source = null!;
    private int _size;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    public string Name => _name;
    public Guid AdvertiserId => _advertiserId;
    public AudienceSource Source => _source;
    public int SourceId { get; private set; }
    public int Size => _size;
    public DateTime CreatedAt => _createdAt;
    public DateTime? UpdatedAt => _updatedAt;

    protected CustomAudience() { }

    public CustomAudience(
        Guid advertiserId,
        string name,
        AudienceSource source,
        int size = 0) : this()
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new AdsDomainException("Audience name cannot be empty");

        Id = Guid.NewGuid();
        _advertiserId = advertiserId;
        _name = name;
        _source = source;
        SourceId = source.Id;
        _size = size;
        _createdAt = DateTime.UtcNow;
    }

    public void UpdateSize(int size)
    {
        _size = size;
        _updatedAt = DateTime.UtcNow;
    }
}

/// <summary>
/// EN: Lookalike Audience - similar users to a source audience.
/// VI: Lookalike Audience - người dùng tương tự với audience nguồn.
/// </summary>
public class LookalikeAudience : Entity, IAggregateRoot
{
    private string _name = null!;
    private Guid _advertiserId;
    private Guid _sourceAudienceId;
    private int _similarityPercentage;
    private string? _location;
    private int _size;
    private DateTime _createdAt;

    public string Name => _name;
    public Guid AdvertiserId => _advertiserId;
    public Guid SourceAudienceId => _sourceAudienceId;
    public int SimilarityPercentage => _similarityPercentage;
    public string? Location => _location;
    public int Size => _size;
    public DateTime CreatedAt => _createdAt;

    protected LookalikeAudience() { }

    public LookalikeAudience(
        Guid advertiserId,
        string name,
        Guid sourceAudienceId,
        int similarityPercentage,
        string? location = null) : this()
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new AdsDomainException("Lookalike audience name cannot be empty");
        
        if (similarityPercentage < 1 || similarityPercentage > 10)
            throw new AdsDomainException("Similarity percentage must be between 1% and 10%");

        Id = Guid.NewGuid();
        _advertiserId = advertiserId;
        _name = name;
        _sourceAudienceId = sourceAudienceId;
        _similarityPercentage = similarityPercentage;
        _location = location;
        _size = 0;
        _createdAt = DateTime.UtcNow;
    }

    public void UpdateSize(int size)
    {
        _size = size;
    }
}

/// <summary>
/// EN: Audience source type.
/// VI: Loại nguồn audience.
/// </summary>
public class AudienceSource : Enumeration
{
    public static readonly AudienceSource CustomerList = new(1, "customer_list");
    public static readonly AudienceSource WebsiteVisitors = new(2, "website_visitors");
    public static readonly AudienceSource AppUsers = new(3, "app_users");
    public static readonly AudienceSource EngagementCustomers = new(4, "engagement_customers");

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

    public static IEnumerable<AudienceSource> List() =>
        new[] { CustomerList, WebsiteVisitors, AppUsers, EngagementCustomers };
}
