using MembershipService.Domain.AggregatesModel.ExperienceAggregate;
using MembershipService.Domain.AggregatesModel.LevelAggregate;
using MembershipService.Domain.Events;
using MembershipService.Domain.SeedWork;

namespace MembershipService.Domain.AggregatesModel.MemberAggregate;

/// <summary>
/// EN: Member aggregate root - extends user information from IAM Service.
/// VI: Member aggregate root - mở rộng thông tin user từ IAM Service.
/// </summary>
/// <remarks>
/// EN: This entity stores membership-specific data. Profile information (avatar, phone, address, DOB)
/// is managed by IAM Service's UserProfile. This service handles level, experience, and preferences.
/// VI: Entity này lưu trữ dữ liệu membership. Thông tin profile (avatar, phone, address, DOB)
/// được quản lý bởi UserProfile của IAM Service. Service này xử lý level, experience, và preferences.
/// </remarks>
public class Member : Entity, IAggregateRoot
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private string _countryCode;
    private string? _gender;
    private int _currentLevel;
    private int _currentExp;
    private int _totalExpEarned;
    private string? _preferences; // JSON string
    private DateTime _createdAt;
    private DateTime _updatedAt;
    private bool _isDeleted;

    /// <summary>
    /// EN: User ID from IAM Service (same as Member.Id).
    /// VI: User ID từ IAM Service (giống Member.Id).
    /// </summary>
    public Guid UserId => Id;

    /// <summary>
    /// EN: Country code (ISO 3166-1 alpha-2).
    /// VI: Mã quốc gia (ISO 3166-1 alpha-2).
    /// </summary>
    public string CountryCode => _countryCode;

    /// <summary>
    /// EN: Gender (male, female, other).
    /// VI: Giới tính (nam, nữ, khác).
    /// </summary>
    public string? Gender => _gender;

    /// <summary>
    /// EN: Current member level.
    /// VI: Level hiện tại của member.
    /// </summary>
    public int CurrentLevel => _currentLevel;

    /// <summary>
    /// EN: Current experience points.
    /// VI: Điểm kinh nghiệm hiện tại.
    /// </summary>
    public int CurrentExp => _currentExp;

    /// <summary>
    /// EN: Total experience points ever earned.
    /// VI: Tổng điểm kinh nghiệm đã kiếm được.
    /// </summary>
    public int TotalExpEarned => _totalExpEarned;

    /// <summary>
    /// EN: User preferences as JSON string.
    /// VI: Preferences của user dạng chuỗi JSON.
    /// </summary>
    public string? Preferences => _preferences;

    /// <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: Soft delete flag.
    /// VI: Cờ xóa mềm.
    /// </summary>
    public bool IsDeleted => _isDeleted;

    /// <summary>
    /// EN: Private constructor for EF Core.
    /// VI: Constructor private cho EF Core.
    /// </summary>
    protected Member()
    {
        _countryCode = "VN"; // Default country code
    }

    /// <summary>
    /// EN: Create new member with user ID from IAM Service.
    /// VI: Tạo member mới với user ID từ IAM Service.
    /// </summary>
    /// <param name="userId">User ID from IAM Service / User ID từ IAM Service</param>
    /// <param name="countryCode">Country code (ISO 3166-1 alpha-2) / Mã quốc gia</param>
    /// <param name="gender">Gender (optional) / Giới tính (tùy chọn)</param>
    public Member(Guid userId, string countryCode = "VN", string? gender = null) : this()
    {
        if (userId == Guid.Empty)
            throw new ArgumentException("User ID cannot be empty", nameof(userId));

        Id = userId;
        _countryCode = countryCode;
        _gender = gender;
        _currentLevel = 1;  // Start at level 1
        _currentExp = 0;
        _totalExpEarned = 0;
        _createdAt = DateTime.UtcNow;
        _updatedAt = DateTime.UtcNow;

        // EN: Add domain event for member creation
        // VI: Thêm domain event khi tạo member
        AddDomainEvent(new MemberCreatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Add experience points and automatically level up if thresholds are met.
    /// VI: Thêm điểm kinh nghiệm và tự động lên level nếu đạt ngưỡng.
    /// </summary>
    /// <param name="points">Amount of EXP to add / Số EXP cộng thêm</param>
    /// <param name="source">Source of experience / Nguồn EXP</param>
    /// <param name="levelRules">Active level definitions / Các level definitions đang active</param>
    /// <param name="referenceId">Reference ID (optional) / ID tham chiếu (tùy chọn)</param>
    /// <param name="metadata">Metadata JSON (optional) / Metadata JSON (tùy chọn)</param>
    /// <returns>ExperienceTransaction for tracking / ExperienceTransaction để tracking</returns>
    public ExperienceTransaction AddExperience(
        int points,
        ExperienceSource source,
        IReadOnlyList<LevelDefinition> levelRules,
        string? referenceId = null,
        string? metadata = null)
    {
        if (points <= 0)
            throw new ArgumentException("EXP points must be positive", nameof(points));
        if (source == null)
            throw new ArgumentNullException(nameof(source));
        if (levelRules == null || !levelRules.Any())
            throw new ArgumentException("Level rules cannot be empty", nameof(levelRules));

        int oldLevel = _currentLevel;

        // EN: Create transaction for tracking
        // VI: Tạo transaction để tracking
        var transaction = new ExperienceTransaction(
            memberId: Id,
            points: points,
            source: source,
            levelAtTime: oldLevel,
            referenceId: referenceId,
            metadata: metadata);

        // EN: Update experience points
        // VI: Cập nhật điểm kinh nghiệm
        _currentExp += points;
        _totalExpEarned += points;
        _updatedAt = DateTime.UtcNow;

        // EN: Calculate new level based on rules
        // VI: Tính level mới dựa trên rules
        var newLevel = CalculateLevel(_currentExp, levelRules);

        // EN: Check if leveled up
        // VI: Kiểm tra có lên level không
        if (newLevel > oldLevel)
        {
            _currentLevel = newLevel;
            // EN: Raise level up event for side effects (rewards, notifications, etc.)
            // VI: Raise level up event cho side effects (rewards, notifications, etc.)
            AddDomainEvent(new MemberLevelUpDomainEvent(this, oldLevel, newLevel));
        }

        // EN: Raise experience added event
        // VI: Raise event khi thêm experience
        AddDomainEvent(new MemberExperienceAddedDomainEvent(this, points, source));

        return transaction;
    }

    /// <summary>
    /// EN: Calculate level based on current EXP and level rules.
    /// VI: Tính level dựa trên EXP hiện tại và level rules.
    /// </summary>
    private static int CalculateLevel(int exp, IReadOnlyList<LevelDefinition> rules)
    {
        return rules
            .Where(r => r.IsActive && r.RequiredExp <= exp)
            .OrderByDescending(r => r.LevelNumber)
            .FirstOrDefault()?.LevelNumber ?? 1;
    }

    /// <summary>
    /// EN: Update gender.
    /// VI: Cập nhật giới tính.
    /// </summary>
    public void UpdateGender(string? gender)
    {
        _gender = gender;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new MemberUpdatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Update country code.
    /// VI: Cập nhật mã quốc gia.
    /// </summary>
    public void UpdateCountryCode(string countryCode)
    {
        if (string.IsNullOrWhiteSpace(countryCode))
            throw new ArgumentException("Country code cannot be empty", nameof(countryCode));

        _countryCode = countryCode;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new MemberUpdatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Update user preferences.
    /// VI: Cập nhật preferences của user.
    /// </summary>
    public void UpdatePreferences(string? preferencesJson)
    {
        _preferences = preferencesJson;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new MemberUpdatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Mark member as deleted (soft delete).
    /// VI: Đánh dấu member đã xóa (xóa mềm).
    /// </summary>
    public void Delete()
    {
        _isDeleted = true;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Restore soft-deleted member.
    /// VI: Khôi phục member đã xóa mềm.
    /// </summary>
    public void Restore()
    {
        _isDeleted = false;
        _updatedAt = DateTime.UtcNow;
    }
}
