namespace ChatService.Domain.AggregatesModel.UserAggregate;

using ChatService.Domain.Events;
using ChatService.Domain.Exceptions;
using ChatService.Domain.SeedWork;

/// <summary>
/// EN: Chat user aggregate root - represents a user in the chat system.
/// VI: Chat user aggregate root - đại diện một user trong hệ thống chat.
/// </summary>
/// <remarks>
/// EN: Links to IAM Service user via IdentityUserId. Contains E2EE public keys.
/// VI: Liên kết với IAM Service user qua IdentityUserId. Chứa E2EE public keys.
/// </remarks>
public class ChatUser : Entity, IAggregateRoot
{
    private string _identityUserId;
    private string _displayName;
    private string? _avatarUrl;
#pragma warning disable CS0169 // Field is used by EF Core
    private int _statusId;
#pragma warning restore CS0169
    private UserStatus _status;
    private UserKeyBundle? _keyBundle;
    private readonly List<OneTimePreKey> _oneTimePreKeys;
    private DateTime _lastSeenAt;
    private DateTime _createdAt;
    private DateTime _updatedAt;

    /// <summary>
    /// EN: Reference to IAM Service user ID.
    /// VI: Tham chiếu đến IAM Service user ID.
    /// </summary>
    public string IdentityUserId => _identityUserId;

    /// <summary>
    /// EN: Display name shown in chat.
    /// VI: Tên hiển thị trong chat.
    /// </summary>
    public string DisplayName => _displayName;

    /// <summary>
    /// EN: URL to user's avatar image.
    /// VI: URL ảnh avatar của user.
    /// </summary>
    public string? AvatarUrl => _avatarUrl;

    /// <summary>
    /// EN: Current online status.
    /// VI: Trạng thái online hiện tại.
    /// </summary>
    public UserStatus Status => _status;

    /// <summary>
    /// EN: E2EE public key bundle.
    /// VI: Bundle E2EE public keys.
    /// </summary>
    public UserKeyBundle? KeyBundle => _keyBundle;

    /// <summary>
    /// EN: Available one-time pre-keys for X3DH.
    /// VI: Các one-time pre-keys khả dụng cho X3DH.
    /// </summary>
    public IReadOnlyCollection<OneTimePreKey> OneTimePreKeys => _oneTimePreKeys.AsReadOnly();

    /// <summary>
    /// EN: Last time user was active.
    /// VI: Lần cuối user hoạt động.
    /// </summary>
    public DateTime LastSeenAt => _lastSeenAt;

    public DateTime CreatedAt => _createdAt;
    public DateTime UpdatedAt => _updatedAt;

    protected ChatUser()
    {
        // EN: Required by EF Core
        // VI: Yêu cầu bởi EF Core
        _identityUserId = string.Empty;
        _displayName = string.Empty;
        _status = UserStatus.Offline;
        _oneTimePreKeys = new List<OneTimePreKey>();
    }

    public ChatUser(string identityUserId, string displayName, string? avatarUrl = null) : this()
    {
        if (string.IsNullOrWhiteSpace(identityUserId))
            throw new ChatDomainException("Identity user ID is required");
        if (string.IsNullOrWhiteSpace(displayName))
            throw new ChatDomainException("Display name is required");

        Id = Guid.NewGuid();
        _identityUserId = identityUserId;
        _displayName = displayName;
        _avatarUrl = avatarUrl;
        _status = UserStatus.Offline;
        _lastSeenAt = DateTime.UtcNow;
        _createdAt = DateTime.UtcNow;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new ChatUserCreatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Register user's E2EE key bundle.
    /// VI: Đăng ký E2EE key bundle của user.
    /// </summary>
    public void RegisterKeyBundle(
        string identityPublicKey,
        string signedPreKey,
        string signedPreKeySignature)
    {
        _keyBundle = new UserKeyBundle(
            identityPublicKey,
            signedPreKey,
            signedPreKeySignature);
        
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new UserKeyBundleUpdatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Rotate signed pre-key.
    /// VI: Xoay vòng signed pre-key.
    /// </summary>
    public void RotateSignedPreKey(string newSignedPreKey, string newSignature)
    {
        if (_keyBundle == null)
            throw new ChatDomainException("Cannot rotate pre-key: no key bundle registered");

        _keyBundle = _keyBundle.RotateSignedPreKey(newSignedPreKey, newSignature);
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new UserKeyBundleUpdatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Upload one-time pre-keys.
    /// VI: Upload các one-time pre-keys.
    /// </summary>
    public void UploadOneTimePreKeys(IEnumerable<(int keyId, string publicKey)> keys)
    {
        foreach (var (keyId, publicKey) in keys)
        {
            // EN: Check for duplicate key IDs
            // VI: Kiểm tra trùng lặp key ID
            if (_oneTimePreKeys.Any(k => k.KeyId == keyId && !k.IsUsed))
                continue;

            var preKey = new OneTimePreKey(Id, keyId, publicKey);
            _oneTimePreKeys.Add(preKey);
        }

        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Consume a one-time pre-key (for key exchange).
    /// VI: Sử dụng một one-time pre-key (cho key exchange).
    /// </summary>
    public OneTimePreKey? ConsumeOneTimePreKey()
    {
        var availableKey = _oneTimePreKeys.FirstOrDefault(k => !k.IsUsed);
        
        if (availableKey != null)
        {
            availableKey.MarkAsUsed();
            _updatedAt = DateTime.UtcNow;
        }

        return availableKey;
    }

    /// <summary>
    /// EN: Get count of available one-time pre-keys.
    /// VI: Lấy số lượng one-time pre-keys khả dụng.
    /// </summary>
    public int GetAvailableOneTimePreKeyCount()
    {
        return _oneTimePreKeys.Count(k => !k.IsUsed);
    }

    /// <summary>
    /// EN: Update display name.
    /// VI: Cập nhật tên hiển thị.
    /// </summary>
    public void UpdateDisplayName(string displayName)
    {
        if (string.IsNullOrWhiteSpace(displayName))
            throw new ChatDomainException("Display name is required");

        _displayName = displayName;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update avatar URL.
    /// VI: Cập nhật URL avatar.
    /// </summary>
    public void UpdateAvatarUrl(string? avatarUrl)
    {
        _avatarUrl = avatarUrl;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set online status.
    /// VI: Đặt trạng thái online.
    /// </summary>
    public void SetOnlineStatus(UserStatus status)
    {
        _status = status;
        _lastSeenAt = DateTime.UtcNow;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update last seen timestamp.
    /// VI: Cập nhật thời gian hoạt động cuối.
    /// </summary>
    public void UpdateLastSeen()
    {
        _lastSeenAt = DateTime.UtcNow;
    }
}
