using System.Security.Cryptography;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel.Args;

public class DocumentStorageService : IDocumentStorageService
{
    private readonly IMinioClient _minio;
    private readonly MinioOptions _options;

    public DocumentStorageService(IMinioClient minio, IOptions<MinioOptions> options)
    {
        _minio = minio;
        _options = options.Value;
    }

    public async Task<(string objectKey, string sha256, long fileSize)> UploadAsync(
        Stream fileStream, string contentType, Guid batchId)
    {
        var now = DateTimeOffset.UtcNow;
        using var sha256 = SHA256.Create();
        using var memStream = new MemoryStream();

        await fileStream.CopyToAsync(memStream);
        memStream.Position = 0;

        var hashBytes = sha256.ComputeHash(memStream);
        var hashHex = Convert.ToHexString(hashBytes).ToLowerInvariant();
        memStream.Position = 0;

        var extension = contentType switch
        {
            "application/pdf" => "pdf",
            "image/jpeg" => "jpg",
            "image/png" => "png",
            _ => "bin"
        };

        var objectKey = $"scans/{now.Year}/{now.Month:D2}/{batchId}/{hashHex}.{extension}";

        await EnsureBucketAsync();

        await _minio.PutObjectAsync(new PutObjectArgs()
            .WithBucket(_options.BucketName)
            .WithObject(objectKey)
            .WithStreamData(memStream)
            .WithObjectSize(memStream.Length)
            .WithContentType(contentType));

        return (objectKey, hashHex, memStream.Length);
    }

    public async Task<string> GetPresignedUrlAsync(string objectKey)
    {
        return await _minio.PresignedGetObjectAsync(new PresignedGetObjectArgs()
            .WithBucket(_options.BucketName)
            .WithObject(objectKey)
            .WithExpiry(_options.PresignedUrlExpiryMinutes * 60));
    }

    public async Task<Stream> DownloadAsync(string objectKey)
    {
        var memStream = new MemoryStream();
        await _minio.GetObjectAsync(new GetObjectArgs()
            .WithBucket(_options.BucketName)
            .WithObject(objectKey)
            .WithCallbackStream(stream => stream.CopyTo(memStream)));

        memStream.Position = 0;
        return memStream;
    }

    private async Task EnsureBucketAsync()
    {
        var exists = await _minio.BucketExistsAsync(new BucketExistsArgs().WithBucket(_options.BucketName));
        if (!exists)
            await _minio.MakeBucketAsync(new MakeBucketArgs().WithBucket(_options.BucketName));
    }
}