using WhatsAppService.Domain.Events;
using WhatsAppService.Domain.Exceptions;
using WhatsAppService.Domain.SeedWork;

namespace WhatsAppService.Domain.AggregatesModel.CustomerAggregate;

/// <summary>
/// EN: Customer aggregate root for managing WhatsApp customer profiles.
/// VI: Customer aggregate root để quản lý hồ sơ khách hàng WhatsApp.
/// </summary>
public class Customer : Entity, IAggregateRoot
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private Guid _shopId;
    private string _waId = null!;
    private string? _name;
    private string? _profilePictureUrl;
    private OptInConsent _consent = null!;
    private List<string> _tags = new();
    private Dictionary<string, string> _customFields = new();
    private DateTime _firstContactedAt;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    /// <summary>
    /// EN: Shop ID that owns this customer.
    /// VI: Shop ID sở hữu customer này.
    /// </summary>
    public Guid ShopId => _shopId;

    /// <summary>
    /// EN: WhatsApp ID (phone number) of the customer.
    /// VI: WhatsApp ID (số điện thoại) của khách hàng.
    /// </summary>
    public string WaId => _waId;

    /// <summary>
    /// EN: Customer's display name.
    /// VI: Tên hiển thị của khách hàng.
    /// </summary>
    public string? Name => _name;

    /// <summary>
    /// EN: Customer's profile picture URL.
    /// VI: URL ảnh đại diện của khách hàng.
    /// </summary>
    public string? ProfilePictureUrl => _profilePictureUrl;

    /// <summary>
    /// EN: Customer's opt-in consent for messaging (GDPR compliant).
    /// VI: Đồng ý nhận tin nhắn của khách hàng (tuân thủ GDPR).
    /// </summary>
    public OptInConsent Consent => _consent;

    /// <summary>
    /// EN: Customer tags for segmentation.
    /// VI: Tags khách hàng để phân khúc.
    /// </summary>
    public IReadOnlyList<string> Tags => _tags.AsReadOnly();

    /// <summary>
    /// EN: Custom fields for extending customer profile.
    /// VI: Custom fields để mở rộng hồ sơ khách hàng.
    /// </summary>
    public IReadOnlyDictionary<string, string> CustomFields => _customFields;

    /// <summary>
    /// EN: Timestamp of first contact.
    /// VI: Thời điểm liên hệ đầu tiên.
    /// </summary>
    public DateTime FirstContactedAt => _firstContactedAt;

    /// <summary>
    /// EN: Creation timestamp.
    /// VI: Thời gian tạo.
    /// </summary>
    public DateTime CreatedAt => _createdAt;

    /// <summary>
    /// EN: Last update timestamp.
    /// VI: Thời gian cập nhật cuối.
    /// </summary>
    public DateTime? UpdatedAt => _updatedAt;

    /// <summary>
    /// EN: Private constructor for EF Core.
    /// VI: Constructor private cho EF Core.
    /// </summary>
    protected Customer()
    {
    }

    /// <summary>
    /// EN: Create a new customer profile.
    /// VI: Tạo một hồ sơ khách hàng mới.
    /// </summary>
    /// <param name="shopId">EN: Shop ID that owns this customer / VI: Shop ID sở hữu customer này</param>
    /// <param name="waId">EN: WhatsApp ID (phone number) / VI: WhatsApp ID (số điện thoại)</param>
    /// <param name="name">EN: Optional display name / VI: Tên hiển thị tùy chọn</param>
    public Customer(Guid shopId, string waId, string? name = null) : this()
    {
        if (shopId == Guid.Empty)
            throw new CustomerDomainException("Shop ID cannot be empty");
        
        if (string.IsNullOrWhiteSpace(waId))
            throw new CustomerDomainException("WhatsApp ID cannot be empty");

        Id = Guid.NewGuid();
        _shopId = shopId;
        _waId = waId.Trim();
        _name = name;
        _consent = OptInConsent.CreatePending();
        _firstContactedAt = DateTime.UtcNow;
        _createdAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update customer's display name.
    /// VI: Cập nhật tên hiển thị của khách hàng.
    /// </summary>
    /// <param name="name">EN: New display name / VI: Tên hiển thị mới</param>
    public void UpdateName(string? name)
    {
        _name = name;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update customer's profile picture URL.
    /// VI: Cập nhật URL ảnh đại diện của khách hàng.
    /// </summary>
    /// <param name="url">EN: Profile picture URL / VI: URL ảnh đại diện</param>
    public void UpdateProfilePicture(string? url)
    {
        _profilePictureUrl = url;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update customer's opt-in consent.
    /// VI: Cập nhật đồng ý nhận tin nhắn của khách hàng.
    /// </summary>
    /// <param name="status">EN: New consent status / VI: Trạng thái đồng ý mới</param>
    /// <param name="source">EN: Source of consent change / VI: Nguồn thay đổi đồng ý</param>
    public void UpdateOptIn(string status, string source)
    {
        var previousConsent = _consent;
        _consent = new OptInConsent(status, source);
        _updatedAt = DateTime.UtcNow;

        // EN: Raise domain event if consent changed
        // VI: Phát domain event nếu đồng ý thay đổi
        if (previousConsent.Status != _consent.Status)
        {
            AddDomainEvent(new CustomerOptInChangedEvent(Id, _shopId, _waId, previousConsent, _consent));
        }
    }

    /// <summary>
    /// EN: Add a tag to the customer.
    /// VI: Thêm một tag vào khách hàng.
    /// </summary>
    /// <param name="tag">EN: Tag to add / VI: Tag cần thêm</param>
    public void AddTag(string tag)
    {
        if (string.IsNullOrWhiteSpace(tag))
            throw new CustomerDomainException("Tag cannot be empty");

        var normalizedTag = tag.Trim().ToLowerInvariant();
        
        if (!_tags.Contains(normalizedTag))
        {
            _tags.Add(normalizedTag);
            _updatedAt = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// EN: Remove a tag from the customer.
    /// VI: Xóa một tag khỏi khách hàng.
    /// </summary>
    /// <param name="tag">EN: Tag to remove / VI: Tag cần xóa</param>
    public void RemoveTag(string tag)
    {
        if (string.IsNullOrWhiteSpace(tag))
            return;

        var normalizedTag = tag.Trim().ToLowerInvariant();
        
        if (_tags.Remove(normalizedTag))
        {
            _updatedAt = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// EN: Update or add a custom field.
    /// VI: Cập nhật hoặc thêm một custom field.
    /// </summary>
    /// <param name="key">EN: Field key / VI: Key của field</param>
    /// <param name="value">EN: Field value / VI: Giá trị của field</param>
    public void UpdateCustomField(string key, string value)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new CustomerDomainException("Custom field key cannot be empty");

        _customFields[key.Trim()] = value;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Remove a custom field.
    /// VI: Xóa một custom field.
    /// </summary>
    /// <param name="key">EN: Field key to remove / VI: Key của field cần xóa</param>
    public void RemoveCustomField(string key)
    {
        if (string.IsNullOrWhiteSpace(key))
            return;

        if (_customFields.Remove(key.Trim()))
        {
            _updatedAt = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// EN: Check if customer has a specific tag.
    /// VI: Kiểm tra xem khách hàng có một tag cụ thể không.
    /// </summary>
    /// <param name="tag">EN: Tag to check / VI: Tag cần kiểm tra</param>
    public bool HasTag(string tag)
    {
        if (string.IsNullOrWhiteSpace(tag))
            return false;

        return _tags.Contains(tag.Trim().ToLowerInvariant());
    }
}
