using IamService.Domain.SeedWork;

namespace IamService.Domain.AggregatesModel.UserAggregate;

/// <summary>
/// EN: Profile attribute entity for storing typed key-value pairs.
/// VI: Entity profile attribute để lưu trữ cặp key-value có kiểu dữ liệu.
/// </summary>
public class ProfileAttribute : Entity
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private Guid _userProfileId;
    private string _key = null!;
    private string _value = null!;
    private ProfileAttributeType _valueType = null!;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

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

    /// <summary>
    /// EN: Attribute key (e.g., "company", "job_title", "preferences.theme").
    /// VI: Key của attribute (ví dụ: "company", "job_title", "preferences.theme").
    /// </summary>
    public string Key => _key;

    /// <summary>
    /// EN: Attribute value stored as string (parsed based on ValueType).
    /// VI: Giá trị attribute lưu dạng chuỗi (parse dựa trên ValueType).
    /// </summary>
    public string Value => _value;

    /// <summary>
    /// EN: Type of the value for proper parsing.
    /// VI: Loại giá trị để parse đúng cách.
    /// </summary>
    public ProfileAttributeType ValueType => _valueType;

    /// <summary>
    /// EN: Value type ID for EF Core mapping.
    /// VI: ID loại giá trị cho EF Core mapping.
    /// </summary>
    public int ValueTypeId { get; private set; }

    /// <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 ProfileAttribute()
    {
    }

    /// <summary>
    /// EN: Create a new profile attribute.
    /// VI: Tạo profile attribute mới.
    /// </summary>
    public ProfileAttribute(
        Guid userProfileId,
        string key,
        string value,
        ProfileAttributeType valueType) : this()
    {
        if (userProfileId == Guid.Empty)
            throw new ArgumentException("User profile ID cannot be empty", nameof(userProfileId));
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException("Attribute key cannot be empty", nameof(key));
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Attribute value cannot be empty", nameof(value));

        Id = Guid.NewGuid();
        _userProfileId = userProfileId;
        _key = key.Trim().ToLowerInvariant();
        _value = value;
        _valueType = valueType ?? ProfileAttributeType.String;
        ValueTypeId = _valueType.Id;
        _createdAt = DateTime.UtcNow;

        // EN: Validate value matches type
        // VI: Kiểm tra giá trị khớp với loại
        ValidateValue();
    }

    /// <summary>
    /// EN: Create a string attribute.
    /// VI: Tạo attribute kiểu chuỗi.
    /// </summary>
    public static ProfileAttribute CreateString(Guid userProfileId, string key, string value)
    {
        return new ProfileAttribute(userProfileId, key, value, ProfileAttributeType.String);
    }

    /// <summary>
    /// EN: Create a number attribute.
    /// VI: Tạo attribute kiểu số.
    /// </summary>
    public static ProfileAttribute CreateNumber(Guid userProfileId, string key, decimal value)
    {
        return new ProfileAttribute(userProfileId, key, value.ToString(), ProfileAttributeType.Number);
    }

    /// <summary>
    /// EN: Create a boolean attribute.
    /// VI: Tạo attribute kiểu boolean.
    /// </summary>
    public static ProfileAttribute CreateBoolean(Guid userProfileId, string key, bool value)
    {
        return new ProfileAttribute(userProfileId, key, value.ToString().ToLowerInvariant(), ProfileAttributeType.Boolean);
    }

    /// <summary>
    /// EN: Create a date attribute.
    /// VI: Tạo attribute kiểu ngày.
    /// </summary>
    public static ProfileAttribute CreateDate(Guid userProfileId, string key, DateTime value)
    {
        return new ProfileAttribute(userProfileId, key, value.ToString("O"), ProfileAttributeType.Date);
    }

    /// <summary>
    /// EN: Create a JSON attribute.
    /// VI: Tạo attribute kiểu JSON.
    /// </summary>
    public static ProfileAttribute CreateJson(Guid userProfileId, string key, string jsonValue)
    {
        return new ProfileAttribute(userProfileId, key, jsonValue, ProfileAttributeType.Json);
    }

    /// <summary>
    /// EN: Update the attribute value.
    /// VI: Cập nhật giá trị attribute.
    /// </summary>
    public void UpdateValue(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Attribute value cannot be empty", nameof(value));

        _value = value;
        _updatedAt = DateTime.UtcNow;
        ValidateValue();
    }

    /// <summary>
    /// EN: Update both value and type.
    /// VI: Cập nhật cả giá trị và loại.
    /// </summary>
    public void Update(string value, ProfileAttributeType valueType)
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Attribute value cannot be empty", nameof(value));

        _value = value;
        _valueType = valueType ?? ProfileAttributeType.String;
        ValueTypeId = _valueType.Id;
        _updatedAt = DateTime.UtcNow;
        ValidateValue();
    }

    /// <summary>
    /// EN: Get value as string.
    /// VI: Lấy giá trị dạng chuỗi.
    /// </summary>
    public string GetAsString() => _value;

    /// <summary>
    /// EN: Get value as number.
    /// VI: Lấy giá trị dạng số.
    /// </summary>
    public decimal? GetAsNumber()
    {
        if (_valueType != ProfileAttributeType.Number)
            return null;
        return decimal.TryParse(_value, out var result) ? result : null;
    }

    /// <summary>
    /// EN: Get value as boolean.
    /// VI: Lấy giá trị dạng boolean.
    /// </summary>
    public bool? GetAsBoolean()
    {
        if (_valueType != ProfileAttributeType.Boolean)
            return null;
        return bool.TryParse(_value, out var result) ? result : null;
    }

    /// <summary>
    /// EN: Get value as DateTime.
    /// VI: Lấy giá trị dạng DateTime.
    /// </summary>
    public DateTime? GetAsDate()
    {
        if (_valueType != ProfileAttributeType.Date)
            return null;
        return DateTime.TryParse(_value, out var result) ? result : null;
    }

    /// <summary>
    /// EN: Validate value matches the declared type.
    /// VI: Kiểm tra giá trị khớp với loại đã khai báo.
    /// </summary>
    private void ValidateValue()
    {
        var isValid = _valueType.Id switch
        {
            2 => decimal.TryParse(_value, out _),  // Number
            3 => bool.TryParse(_value, out _),     // Boolean
            4 => DateTime.TryParse(_value, out _), // Date
            5 => IsValidJson(_value),              // Json
            _ => true                              // String - always valid
        };

        if (!isValid)
        {
            throw new ArgumentException(
                $"Value '{_value}' is not valid for type '{_valueType.Name}'",
                nameof(_value));
        }
    }

    /// <summary>
    /// EN: Check if string is valid JSON.
    /// VI: Kiểm tra chuỗi có phải JSON hợp lệ không.
    /// </summary>
    private static bool IsValidJson(string value)
    {
        try
        {
            System.Text.Json.JsonDocument.Parse(value);
            return true;
        }
        catch
        {
            return false;
        }
    }
}
