using StorageService.Domain.SeedWork;

namespace StorageService.Domain.AggregatesModel.FileAggregate;

/// <summary>
/// EN: Represents a file stored in the storage system.
/// VI: Đại diện cho file được lưu trữ trong hệ thống.
/// </summary>
public class StorageFile : Entity, IAggregateRoot
{
    /// <summary>EN: Original file name / VI: Tên file gốc</summary>
    public string FileName { get; private set; } = string.Empty;
    
    /// <summary>EN: Bucket/container name / VI: Tên bucket/container</summary>
    public string BucketName { get; private set; } = string.Empty;
    
    /// <summary>EN: Unique key in storage / VI: Key duy nhất trong storage</summary>
    public string ObjectKey { get; private set; } = string.Empty;
    
    /// <summary>EN: MIME content type / VI: MIME content type</summary>
    public string ContentType { get; private set; } = string.Empty;
    
    /// <summary>EN: File size in bytes / VI: Kích thước file (bytes)</summary>
    public long FileSizeBytes { get; private set; }
    
    /// <summary>EN: Owner user ID / VI: ID người dùng sở hữu</summary>
    public string UserId { get; private set; } = string.Empty;
    
    /// <summary>EN: Tenant ID for multi-tenancy / VI: Tenant ID cho multi-tenancy</summary>
    public string? TenantId { get; private set; }
    
    /// <summary>EN: Storage provider used / VI: Provider lưu trữ được sử dụng</summary>
    public StorageProvider Provider { get; private set; }
    
    /// <summary>EN: Access level for the file / VI: Mức độ truy cập của file</summary>
    public FileAccessLevel AccessLevel { get; private set; }
    
    /// <summary>EN: Upload timestamp / VI: Thời gian upload</summary>
    public DateTime UploadedAt { get; private set; }
    
    /// <summary>EN: Last access timestamp / VI: Thời gian truy cập cuối</summary>
    public DateTime? LastAccessedAt { get; private set; }
    
    /// <summary>EN: Expiration timestamp (for temporary files) / VI: Thời gian hết hạn (cho file tạm)</summary>
    public DateTime? ExpiresAt { get; private set; }
    
    /// <summary>EN: File checksum (MD5/SHA256) / VI: Checksum file (MD5/SHA256)</summary>
    public string? Checksum { get; private set; }
    
    /// <summary>EN: Soft delete flag / VI: Cờ xóa mềm</summary>
    public bool IsDeleted { get; private set; }
    
    /// <summary>EN: Deleted timestamp / VI: Thời gian xóa</summary>
    public DateTime? DeletedAt { get; private set; }

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

    /// <summary>
    /// EN: Create a new storage file.
    /// VI: Tạo một storage file mới.
    /// </summary>
    public StorageFile(
        string fileName,
        string bucketName,
        string objectKey,
        string contentType,
        long fileSizeBytes,
        string userId,
        StorageProvider provider,
        FileAccessLevel accessLevel = FileAccessLevel.Private,
        string? tenantId = null,
        string? checksum = null)
    {
        Id = Guid.NewGuid();
        FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
        BucketName = bucketName ?? throw new ArgumentNullException(nameof(bucketName));
        ObjectKey = objectKey ?? throw new ArgumentNullException(nameof(objectKey));
        ContentType = contentType ?? "application/octet-stream";
        FileSizeBytes = fileSizeBytes;
        UserId = userId ?? throw new ArgumentNullException(nameof(userId));
        Provider = provider;
        AccessLevel = accessLevel;
        TenantId = tenantId;
        Checksum = checksum;
        UploadedAt = DateTime.UtcNow;
        IsDeleted = false;

        // EN: Raise domain event / VI: Phát domain event
        AddDomainEvent(new FileUploadedDomainEvent(Id, fileName, userId, fileSizeBytes));
    }

    /// <summary>
    /// EN: Mark file as accessed.
    /// VI: Đánh dấu file đã được truy cập.
    /// </summary>
    public void MarkAccessed()
    {
        LastAccessedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update access level.
    /// VI: Cập nhật mức độ truy cập.
    /// </summary>
    public void UpdateAccessLevel(FileAccessLevel newLevel)
    {
        if (IsDeleted)
            throw new InvalidOperationException("Cannot update deleted file");
            
        AccessLevel = newLevel;
    }

    /// <summary>
    /// EN: Soft delete the file.
    /// VI: Xóa mềm file.
    /// </summary>
    public void Delete()
    {
        if (IsDeleted)
            return;
            
        IsDeleted = true;
        DeletedAt = DateTime.UtcNow;
        
        AddDomainEvent(new FileDeletedDomainEvent(Id, UserId, FileSizeBytes));
    }

    /// <summary>
    /// EN: Set expiration time.
    /// VI: Đặt thời gian hết hạn.
    /// </summary>
    public void SetExpiration(DateTime expiresAt)
    {
        if (expiresAt <= DateTime.UtcNow)
            throw new ArgumentException("Expiration must be in the future", nameof(expiresAt));
            
        ExpiresAt = expiresAt;
    }

    /// <summary>
    /// EN: Update file from a restored version.
    /// VI: Cập nhật file từ version được khôi phục.
    /// </summary>
    public void UpdateFromVersion(string objectKey, long sizeBytes, string contentType)
    {
        if (IsDeleted)
            throw new InvalidOperationException("Cannot update deleted file");

        ObjectKey = objectKey;
        FileSizeBytes = sizeBytes;
        ContentType = contentType;
    }
}
