using StorageService.Domain.AggregatesModel.FileAggregate;

namespace StorageService.Infrastructure.Storage;

/// <summary>
/// EN: Storage operation result.
/// VI: Kết quả thao tác storage.
/// </summary>
public class StorageResult
{
    public bool Success { get; set; }
    public string? ObjectKey { get; set; }
    public string? DownloadUrl { get; set; }
    public string? Error { get; set; }
    public long? SizeBytes { get; set; }
    public string? Checksum { get; set; }
    
    public static StorageResult Ok(string objectKey, long? sizeBytes = null, string? checksum = null) 
        => new() { Success = true, ObjectKey = objectKey, SizeBytes = sizeBytes, Checksum = checksum };
    
    public static StorageResult Fail(string error) 
        => new() { Success = false, Error = error };
}

/// <summary>
/// EN: Interface for storage providers (MinIO, Aliyun OSS, etc.).
/// VI: Interface cho các storage provider (MinIO, Aliyun OSS, v.v.).
/// </summary>
public interface IStorageProvider
{
    /// <summary>EN: Provider type / VI: Loại provider</summary>
    StorageProvider ProviderType { get; }
    
    /// <summary>
    /// EN: Upload file to storage.
    /// VI: Upload file lên storage.
    /// </summary>
    Task<StorageResult> UploadAsync(
        string bucketName,
        string objectKey,
        Stream dataStream,
        string contentType,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Download file from storage.
    /// VI: Download file từ storage.
    /// </summary>
    Task<Stream?> DownloadAsync(
        string bucketName,
        string objectKey,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Delete file from storage.
    /// VI: Xóa file khỏi storage.
    /// </summary>
    Task<bool> DeleteAsync(
        string bucketName,
        string objectKey,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Check if file exists.
    /// VI: Kiểm tra file có tồn tại.
    /// </summary>
    Task<bool> ExistsAsync(
        string bucketName,
        string objectKey,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Generate pre-signed URL for download.
    /// VI: Tạo pre-signed URL để download.
    /// </summary>
    Task<string> GetPreSignedDownloadUrlAsync(
        string bucketName,
        string objectKey,
        int expirationSeconds = 3600,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Generate pre-signed URL for upload.
    /// VI: Tạo pre-signed URL để upload.
    /// </summary>
    Task<string> GetPreSignedUploadUrlAsync(
        string bucketName,
        string objectKey,
        int expirationSeconds = 3600,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Ensure bucket exists (create if not).
    /// VI: Đảm bảo bucket tồn tại (tạo nếu chưa có).
    /// </summary>
    Task EnsureBucketExistsAsync(
        string bucketName,
        CancellationToken cancellationToken = default);
    
    // ========== Multipart Upload Methods ==========
    
    /// <summary>
    /// EN: Initiate a multipart upload session.
    /// VI: Khởi tạo phiên multipart upload.
    /// </summary>
    /// <returns>Upload ID from provider</returns>
    Task<string> InitiateMultipartUploadAsync(
        string bucketName,
        string objectKey,
        string contentType,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Upload a single part of a multipart upload.
    /// VI: Upload một part của multipart upload.
    /// </summary>
    /// <returns>ETag of the uploaded part</returns>
    Task<string> UploadPartAsync(
        string bucketName,
        string objectKey,
        string uploadId,
        int partNumber,
        Stream dataStream,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Complete a multipart upload by merging all parts.
    /// VI: Hoàn thành multipart upload bằng cách merge tất cả parts.
    /// </summary>
    Task CompleteMultipartUploadAsync(
        string bucketName,
        string objectKey,
        string uploadId,
        List<PartETag> parts,
        CancellationToken cancellationToken = default);
    
    /// <summary>
    /// EN: Abort a multipart upload and cleanup all parts.
    /// VI: Hủy multipart upload và cleanup tất cả parts.
    /// </summary>
    Task AbortMultipartUploadAsync(
        string bucketName,
        string objectKey,
        string uploadId,
        CancellationToken cancellationToken = default);
}

/// <summary>
/// EN: Represents a part ETag for multipart upload completion.
/// VI: Đại diện cho ETag của một part cho multipart upload completion.
/// </summary>
public record PartETag(int PartNumber, string ETag);
