using IamService.Domain.SeedWork;

namespace IamService.Domain.AggregatesModel.UserAggregate;

/// <summary>
/// EN: Extended user profile with custom attributes.
/// VI: Profile user mở rộng với custom attributes.
/// </summary>
public class UserProfile : Entity
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private Guid _userId;
    private string? _bio;
    private string? _avatarUrl;
    private PhoneNumber? _phoneNumber;
    private Address? _address;
    private string? _timezone;
    private string? _locale;
    private DateTime? _dateOfBirth;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    private readonly List<ProfileAttribute> _attributes = [];

    /// <summary>
    /// EN: User ID this profile belongs to.
    /// VI: ID user mà profile này thuộc về.
    /// </summary>
    public Guid UserId => _userId;

    /// <summary>
    /// EN: User bio/about text.
    /// VI: Tiểu sử/giới thiệu user.
    /// </summary>
    public string? Bio => _bio;

    /// <summary>
    /// EN: Profile picture URL.
    /// VI: URL ảnh đại diện.
    /// </summary>
    public string? AvatarUrl => _avatarUrl;

    /// <summary>
    /// EN: User's phone number.
    /// VI: Số điện thoại của user.
    /// </summary>
    public PhoneNumber? PhoneNumber => _phoneNumber;

    /// <summary>
    /// EN: User's address.
    /// VI: Địa chỉ của user.
    /// </summary>
    public Address? Address => _address;

    /// <summary>
    /// EN: User's preferred timezone (IANA format).
    /// VI: Múi giờ ưa thích của user (định dạng IANA).
    /// </summary>
    public string? Timezone => _timezone;

    /// <summary>
    /// EN: User's preferred locale (e.g., vi-VN, en-US).
    /// VI: Locale ưa thích của user (ví dụ: vi-VN, en-US).
    /// </summary>
    public string? Locale => _locale;

    /// <summary>
    /// EN: User's date of birth.
    /// VI: Ngày sinh của user.
    /// </summary>
    public DateTime? DateOfBirth => _dateOfBirth;

    /// <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: Profile attributes collection.
    /// VI: Collection profile attributes.
    /// </summary>
    public IReadOnlyCollection<ProfileAttribute> Attributes => _attributes.AsReadOnly();

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

    /// <summary>
    /// EN: Create a new user profile.
    /// VI: Tạo profile user mới.
    /// </summary>
    public UserProfile(Guid userId) : this()
    {
        if (userId == Guid.Empty)
            throw new ArgumentException("User ID cannot be empty", nameof(userId));

        Id = Guid.NewGuid();
        _userId = userId;
        _createdAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Factory method to create profile.
    /// VI: Factory method để tạo profile.
    /// </summary>
    public static UserProfile Create(Guid userId)
    {
        return new UserProfile(userId);
    }

    /// <summary>
    /// EN: Update basic profile information.
    /// VI: Cập nhật thông tin profile cơ bản.
    /// </summary>
    public void UpdateBasicInfo(string? bio, string? timezone, string? locale)
    {
        _bio = bio?.Trim();
        _timezone = timezone?.Trim();
        _locale = locale?.Trim();
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set avatar URL.
    /// VI: Đặt URL ảnh đại diện.
    /// </summary>
    public void SetAvatar(string? avatarUrl)
    {
        _avatarUrl = avatarUrl?.Trim();
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set phone number.
    /// VI: Đặt số điện thoại.
    /// </summary>
    public void SetPhoneNumber(PhoneNumber? phoneNumber)
    {
        _phoneNumber = phoneNumber;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set address.
    /// VI: Đặt địa chỉ.
    /// </summary>
    public void SetAddress(Address? address)
    {
        _address = address;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set date of birth.
    /// VI: Đặt ngày sinh.
    /// </summary>
    public void SetDateOfBirth(DateTime? dateOfBirth)
    {
        if (dateOfBirth.HasValue && dateOfBirth.Value > DateTime.UtcNow)
            throw new ArgumentException("Date of birth cannot be in the future", nameof(dateOfBirth));

        _dateOfBirth = dateOfBirth;
        _updatedAt = DateTime.UtcNow;
    }

    #region Attribute Management

    /// <summary>
    /// EN: Set a string attribute.
    /// VI: Đặt attribute kiểu chuỗi.
    /// </summary>
    public ProfileAttribute SetAttribute(string key, string value)
    {
        var existing = GetAttributeEntity(key);
        if (existing != null)
        {
            existing.Update(value, ProfileAttributeType.String);
            _updatedAt = DateTime.UtcNow;
            return existing;
        }

        var attribute = ProfileAttribute.CreateString(Id, key, value);
        _attributes.Add(attribute);
        _updatedAt = DateTime.UtcNow;
        return attribute;
    }

    /// <summary>
    /// EN: Set a number attribute.
    /// VI: Đặt attribute kiểu số.
    /// </summary>
    public ProfileAttribute SetAttribute(string key, decimal value)
    {
        var existing = GetAttributeEntity(key);
        if (existing != null)
        {
            existing.Update(value.ToString(), ProfileAttributeType.Number);
            _updatedAt = DateTime.UtcNow;
            return existing;
        }

        var attribute = ProfileAttribute.CreateNumber(Id, key, value);
        _attributes.Add(attribute);
        _updatedAt = DateTime.UtcNow;
        return attribute;
    }

    /// <summary>
    /// EN: Set a boolean attribute.
    /// VI: Đặt attribute kiểu boolean.
    /// </summary>
    public ProfileAttribute SetAttribute(string key, bool value)
    {
        var existing = GetAttributeEntity(key);
        if (existing != null)
        {
            existing.Update(value.ToString().ToLowerInvariant(), ProfileAttributeType.Boolean);
            _updatedAt = DateTime.UtcNow;
            return existing;
        }

        var attribute = ProfileAttribute.CreateBoolean(Id, key, value);
        _attributes.Add(attribute);
        _updatedAt = DateTime.UtcNow;
        return attribute;
    }

    /// <summary>
    /// EN: Set a date attribute.
    /// VI: Đặt attribute kiểu ngày.
    /// </summary>
    public ProfileAttribute SetAttribute(string key, DateTime value)
    {
        var existing = GetAttributeEntity(key);
        if (existing != null)
        {
            existing.Update(value.ToString("O"), ProfileAttributeType.Date);
            _updatedAt = DateTime.UtcNow;
            return existing;
        }

        var attribute = ProfileAttribute.CreateDate(Id, key, value);
        _attributes.Add(attribute);
        _updatedAt = DateTime.UtcNow;
        return attribute;
    }

    /// <summary>
    /// EN: Set a JSON attribute.
    /// VI: Đặt attribute kiểu JSON.
    /// </summary>
    public ProfileAttribute SetJsonAttribute(string key, string jsonValue)
    {
        var existing = GetAttributeEntity(key);
        if (existing != null)
        {
            existing.Update(jsonValue, ProfileAttributeType.Json);
            _updatedAt = DateTime.UtcNow;
            return existing;
        }

        var attribute = ProfileAttribute.CreateJson(Id, key, jsonValue);
        _attributes.Add(attribute);
        _updatedAt = DateTime.UtcNow;
        return attribute;
    }

    /// <summary>
    /// EN: Remove an attribute by key.
    /// VI: Xóa attribute theo key.
    /// </summary>
    public bool RemoveAttribute(string key)
    {
        var attribute = GetAttributeEntity(key);
        if (attribute == null)
            return false;

        _attributes.Remove(attribute);
        _updatedAt = DateTime.UtcNow;
        return true;
    }

    /// <summary>
    /// EN: Get attribute value as string.
    /// VI: Lấy giá trị attribute dạng chuỗi.
    /// </summary>
    public string? GetAttributeValue(string key)
    {
        return GetAttributeEntity(key)?.GetAsString();
    }

    /// <summary>
    /// EN: Get attribute value as number.
    /// VI: Lấy giá trị attribute dạng số.
    /// </summary>
    public decimal? GetAttributeAsNumber(string key)
    {
        return GetAttributeEntity(key)?.GetAsNumber();
    }

    /// <summary>
    /// EN: Get attribute value as boolean.
    /// VI: Lấy giá trị attribute dạng boolean.
    /// </summary>
    public bool? GetAttributeAsBoolean(string key)
    {
        return GetAttributeEntity(key)?.GetAsBoolean();
    }

    /// <summary>
    /// EN: Get attribute value as DateTime.
    /// VI: Lấy giá trị attribute dạng DateTime.
    /// </summary>
    public DateTime? GetAttributeAsDate(string key)
    {
        return GetAttributeEntity(key)?.GetAsDate();
    }

    /// <summary>
    /// EN: Check if attribute exists.
    /// VI: Kiểm tra attribute có tồn tại không.
    /// </summary>
    public bool HasAttribute(string key)
    {
        return GetAttributeEntity(key) != null;
    }

    /// <summary>
    /// EN: Get attribute entity by key.
    /// VI: Lấy entity attribute theo key.
    /// </summary>
    private ProfileAttribute? GetAttributeEntity(string key)
    {
        return _attributes.FirstOrDefault(a => a.Key == key.ToLowerInvariant().Trim());
    }

    #endregion

    /// <summary>
    /// EN: Calculate user's age.
    /// VI: Tính tuổi của user.
    /// </summary>
    public int? GetAge()
    {
        if (!_dateOfBirth.HasValue)
            return null;

        var today = DateTime.UtcNow;
        var age = today.Year - _dateOfBirth.Value.Year;
        
        if (_dateOfBirth.Value.Date > today.AddYears(-age))
            age--;

        return age;
    }
}
