using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Domain.SeedWork;

namespace StorageService.Domain.AggregatesModel.QuotaAggregate;

/// <summary>
/// EN: Represents a user's storage quota and usage.
/// VI: Đại diện cho quota và usage lưu trữ của user.
/// </summary>
public class UserStorageQuota : Entity, IAggregateRoot
{
    /// <summary>EN: User ID / VI: ID người dùng</summary>
    public string UserId { get; private set; } = string.Empty;
    
    /// <summary>EN: Maximum storage in bytes / VI: Dung lượng tối đa (bytes)</summary>
    public long MaxStorageBytes { get; private set; }
    
    /// <summary>EN: Currently used storage in bytes / VI: Dung lượng đã sử dụng (bytes)</summary>
    public long UsedStorageBytes { get; private set; }
    
    /// <summary>EN: Maximum number of files / VI: Số file tối đa</summary>
    public int MaxFileCount { get; private set; }
    
    /// <summary>EN: Current file count / VI: Số file hiện tại</summary>
    public int CurrentFileCount { get; private set; }
    
    /// <summary>EN: Quota tier/plan name / VI: Tên tier/plan quota</summary>
    public string? QuotaTier { get; private set; }
    
    /// <summary>EN: Last updated timestamp / VI: Thời gian cập nhật cuối</summary>
    public DateTime LastUpdatedAt { get; private set; }
    
    /// <summary>EN: Created timestamp / VI: Thời gian tạo</summary>
    public DateTime CreatedAt { get; private set; }

    // EN: EF Core requires parameterless constructor / VI: EF Core cần constructor không tham số
    protected UserStorageQuota() { }

    /// <summary>
    /// EN: Create a new user storage quota.
    /// VI: Tạo quota lưu trữ mới cho user.
    /// </summary>
    public UserStorageQuota(
        string userId,
        long maxStorageBytes = 1073741824, // 1GB default
        int maxFileCount = 1000,
        string? quotaTier = "free")
    {
        Id = Guid.NewGuid();
        UserId = userId ?? throw new ArgumentNullException(nameof(userId));
        MaxStorageBytes = maxStorageBytes;
        MaxFileCount = maxFileCount;
        QuotaTier = quotaTier;
        UsedStorageBytes = 0;
        CurrentFileCount = 0;
        CreatedAt = DateTime.UtcNow;
        LastUpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Get remaining storage in bytes.
    /// VI: Lấy dung lượng còn lại (bytes).
    /// </summary>
    public long RemainingStorageBytes => Math.Max(0, MaxStorageBytes - UsedStorageBytes);

    /// <summary>
    /// EN: Get remaining file count.
    /// VI: Lấy số file còn có thể upload.
    /// </summary>
    public int RemainingFileCount => Math.Max(0, MaxFileCount - CurrentFileCount);

    /// <summary>
    /// EN: Get usage percentage.
    /// VI: Lấy phần trăm sử dụng.
    /// </summary>
    public double UsagePercentage => MaxStorageBytes > 0 
        ? Math.Round((double)UsedStorageBytes / MaxStorageBytes * 100, 2) 
        : 0;

    /// <summary>
    /// EN: Check if user can upload file with given size.
    /// VI: Kiểm tra user có thể upload file với kích thước cho trước.
    /// </summary>
    public bool CanUpload(long fileSizeBytes)
    {
        return UsedStorageBytes + fileSizeBytes <= MaxStorageBytes 
            && CurrentFileCount < MaxFileCount;
    }

    /// <summary>
    /// EN: Add storage usage after upload.
    /// VI: Thêm usage sau khi upload.
    /// </summary>
    public void AddUsage(long fileSizeBytes, int fileCount = 1)
    {
        if (fileSizeBytes < 0)
            throw new ArgumentException("File size cannot be negative", nameof(fileSizeBytes));
            
        UsedStorageBytes += fileSizeBytes;
        CurrentFileCount += fileCount;
        LastUpdatedAt = DateTime.UtcNow;
        
        AddDomainEvent(new UserQuotaUpdatedDomainEvent(UserId, UsedStorageBytes, CurrentFileCount));
    }

    /// <summary>
    /// EN: Remove storage usage after delete.
    /// VI: Giảm usage sau khi xóa.
    /// </summary>
    public void RemoveUsage(long fileSizeBytes, int fileCount = 1)
    {
        if (fileSizeBytes < 0)
            throw new ArgumentException("File size cannot be negative", nameof(fileSizeBytes));
            
        UsedStorageBytes = Math.Max(0, UsedStorageBytes - fileSizeBytes);
        CurrentFileCount = Math.Max(0, CurrentFileCount - fileCount);
        LastUpdatedAt = DateTime.UtcNow;
        
        AddDomainEvent(new UserQuotaUpdatedDomainEvent(UserId, UsedStorageBytes, CurrentFileCount));
    }

    /// <summary>
    /// EN: Update quota limits.
    /// VI: Cập nhật giới hạn quota.
    /// </summary>
    public void UpdateLimits(long maxStorageBytes, int maxFileCount, string? quotaTier = null)
    {
        if (maxStorageBytes < UsedStorageBytes)
            throw new InvalidOperationException($"Cannot set max storage below current usage ({UsedStorageBytes} bytes)");
            
        if (maxFileCount < CurrentFileCount)
            throw new InvalidOperationException($"Cannot set max file count below current count ({CurrentFileCount})");
            
        MaxStorageBytes = maxStorageBytes;
        MaxFileCount = maxFileCount;
        if (quotaTier != null)
            QuotaTier = quotaTier;
        LastUpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Recalculate usage (for sync purposes).
    /// VI: Tính lại usage (để sync).
    /// </summary>
    public void RecalculateUsage(long totalBytes, int totalFiles)
    {
        UsedStorageBytes = Math.Max(0, totalBytes);
        CurrentFileCount = Math.Max(0, totalFiles);
        LastUpdatedAt = DateTime.UtcNow;
    }
}
