using WhatsAppService.Domain.SeedWork;

namespace WhatsAppService.Domain.AggregatesModel.CustomerAggregate;

/// <summary>
/// EN: Value object representing customer's opt-in consent for WhatsApp messaging.
/// VI: Value object đại diện cho sự đồng ý nhận tin nhắn WhatsApp của khách hàng.
/// </summary>
public class OptInConsent : ValueObject
{
    /// <summary>
    /// EN: Consent status (OptedIn, OptedOut, Pending).
    /// VI: Trạng thái đồng ý (OptedIn, OptedOut, Pending).
    /// </summary>
    public string Status { get; private set; }

    /// <summary>
    /// EN: Timestamp when consent was given or changed.
    /// VI: Thời điểm đồng ý được cấp hoặc thay đổi.
    /// </summary>
    public DateTime? Timestamp { get; private set; }

    /// <summary>
    /// EN: Source of consent (Web, WhatsApp, Manual).
    /// VI: Nguồn đồng ý (Web, WhatsApp, Manual).
    /// </summary>
    public string? Source { get; private set; }

    /// <summary>
    /// EN: Valid consent status values.
    /// VI: Các giá trị trạng thái đồng ý hợp lệ.
    /// </summary>
    public static class Statuses
    {
        public const string OptedIn = "opted_in";
        public const string OptedOut = "opted_out";
        public const string Pending = "pending";
    }

    /// <summary>
    /// EN: Valid consent source values.
    /// VI: Các giá trị nguồn đồng ý hợp lệ.
    /// </summary>
    public static class Sources
    {
        public const string Web = "web";
        public const string WhatsApp = "whatsapp";
        public const string Manual = "manual";
    }

    /// <summary>
    /// EN: Private constructor for EF Core.
    /// VI: Constructor private cho EF Core.
    /// </summary>
    private OptInConsent()
    {
        Status = Statuses.Pending;
    }

    /// <summary>
    /// EN: Create a new OptInConsent value object.
    /// VI: Tạo một OptInConsent value object mới.
    /// </summary>
    /// <param name="status">EN: Consent status / VI: Trạng thái đồng ý</param>
    /// <param name="source">EN: Source of consent / VI: Nguồn đồng ý</param>
    public OptInConsent(string status, string? source = null)
    {
        var validStatuses = new[] { Statuses.OptedIn, Statuses.OptedOut, Statuses.Pending };
        if (!validStatuses.Contains(status.ToLowerInvariant()))
            throw new ArgumentException($"Invalid consent status. Valid values: {string.Join(", ", validStatuses)}");

        if (!string.IsNullOrWhiteSpace(source))
        {
            var validSources = new[] { Sources.Web, Sources.WhatsApp, Sources.Manual };
            if (!validSources.Contains(source.ToLowerInvariant()))
                throw new ArgumentException($"Invalid consent source. Valid values: {string.Join(", ", validSources)}");
        }

        Status = status.ToLowerInvariant();
        Source = source?.ToLowerInvariant();
        Timestamp = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Create a pending consent.
    /// VI: Tạo một đồng ý đang chờ.
    /// </summary>
    public static OptInConsent CreatePending() => new(Statuses.Pending);

    /// <summary>
    /// EN: Create an opted-in consent.
    /// VI: Tạo một đồng ý đã chấp nhận.
    /// </summary>
    /// <param name="source">EN: Source of consent / VI: Nguồn đồng ý</param>
    public static OptInConsent CreateOptedIn(string source) => new(Statuses.OptedIn, source);

    /// <summary>
    /// EN: Create an opted-out consent.
    /// VI: Tạo một đồng ý đã từ chối.
    /// </summary>
    /// <param name="source">EN: Source of opt-out / VI: Nguồn từ chối</param>
    public static OptInConsent CreateOptedOut(string source) => new(Statuses.OptedOut, source);

    /// <summary>
    /// EN: Check if customer has opted in.
    /// VI: Kiểm tra xem khách hàng đã đồng ý chưa.
    /// </summary>
    public bool IsOptedIn => Status == Statuses.OptedIn;

    /// <summary>
    /// EN: Check if customer has opted out.
    /// VI: Kiểm tra xem khách hàng đã từ chối chưa.
    /// </summary>
    public bool IsOptedOut => Status == Statuses.OptedOut;

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return Status;
        yield return Timestamp ?? DateTime.MinValue;
        yield return Source ?? string.Empty;
    }
}
