
// 








using Minio;
using Minio.Exceptions;

namespace SafeCampus.System;

/// <summary>
/// Minio功能类
/// </summary>
public class MinioUtils : ITransient
{
    public MinioClient MinioClient;
    private string _defaultBucketName;
    private string _defaultEndPoint;
    private string _defaultPrefix = "http://";
    private readonly IConfigService _configService;

    public MinioUtils(IConfigService configService)
    {
        _configService = configService;
        InitClient();
    }

    /// <summary>
    /// 初始化操作
    /// </summary>
    /// <returns></returns>
    private async void InitClient()
    {
        var configs = await _configService.GetConfigsByCategory(CateGoryConst.CONFIG_FILE_MINIO);//获取minio配置
        var accessKey = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_ACCESS_KEY).FirstOrDefault();//MINIO文件AccessKey
        var secretKey = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_SECRET_KEY).FirstOrDefault();//MINIO文件SecretKey
        var endPoint = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_END_POINT).FirstOrDefault();//MINIO文件EndPoint
        var bucketName = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_DEFAULT_BUCKET_NAME).FirstOrDefault();//MINIO文件默认存储桶
        if (accessKey == null || secretKey == null || endPoint == null || bucketName == null)
        {
            throw Oops.Oh("MINIO客户端未正确配置");
        }
        try
        {
            //默认值赋值
            _defaultBucketName = bucketName.ConfigValue;
            _defaultEndPoint = endPoint.ConfigValue;
            if (_defaultEndPoint.ToLower().StartsWith("http"))
            {
                var point = _defaultEndPoint.Split("//").ToList();//分割、
                _defaultPrefix = $"{point[0]}//";
                _defaultEndPoint = point[1];
            }
            MinioClient = new MinioClient().WithEndpoint(_defaultEndPoint).WithCredentials(accessKey.ConfigValue, secretKey.ConfigValue)
                .Build();//初始化minio对象
            MinioClient.WithTimeout(5000);//超时时间
        }
        catch (Exception ex)
        {
            throw Oops.Oh("MINIO客户端启动失败", ex);
        }
    }

    /// <summary>
    /// 上传文件 - 返回Minio文件完整Url
    /// </summary>
    /// <param name="objectName">存储桶里的对象名称,例:/mnt/photos/island.jpg</param>
    /// <param name="file">文件</param>
    /// <param name="contentType">文件的Content type，默认是"application/octet-stream"</param>
    /// <returns></returns>
    public async Task<string> PutObjectAsync(string objectName, IFormFile file, string contentType = "application/octet-stream")
    {
        try
        {
            using var fileStream = file.OpenReadStream();//获取文件流
            var putObjectArgs = new PutObjectArgs().WithBucket(_defaultBucketName).WithObject(objectName).WithStreamData(fileStream)
                .WithObjectSize(file.Length).WithContentType(contentType);
            await MinioClient.PutObjectAsync(putObjectArgs);
            return $"{_defaultPrefix}{_defaultEndPoint}/{_defaultBucketName}/{objectName}";//默认http
        }
        catch (MinioException e)
        {
            throw Oops.Oh("上传文件失败!", e);
        }
        catch (Exception e)
        {
            throw Oops.Oh("上传文件失败!", e);
        }
    }

    /// <summary>
    /// 下载文件
    /// </summary>
    /// <param name="objectName"></param>
    /// <returns></returns>
    public async Task<MemoryStream> DownloadFileAsync(string objectName)
    {
        var stream = new MemoryStream();
        try
        {
            var getObjectArgs = new GetObjectArgs().WithBucket(_defaultBucketName).WithObject(objectName).WithCallbackStream(cb =>
            {
                cb.CopyTo(stream);
            });
            await MinioClient.GetObjectAsync(getObjectArgs);

            //UserCenter.InvalidOperationException: Response Content-Length mismatch: too few bytes written (0 of 30788)
            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }
            return stream;
        }
        catch (MinioException e)
        {
            throw Oops.Oh("下载文件失败!", e);
        }
        catch (Exception e)
        {
            throw Oops.Oh("下载文件失败!", e);
        }
    }
}
