using Aliyun.OSS;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Minio.DataModel.Args;
using Minio;
using SharpCompress.Common;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace IRaCIS.Core.Application.Helper
{
    public class MinIOOptions : AWSOptions
    {
        public int port { get; set; }

    }

    public class AWSOptions
    {
        public string endPoint { get; set; }
        public bool useSSL { get; set; }
        public string accessKey { get; set; }
        public string secretKey { get; set; }
        public string bucketName { get; set; }
        public string viewEndpoint { get; set; }
    }

    public class AliyunOSSOptions
    {
        public string regionId { get; set; }
        public string accessKeyId { get; set; }
        public string accessKeySecret { get; set; }

        public string internalEndpoint { get; set; }

        public string endPoint { get; set; }
        public string bucketName { get; set; }

        public string roleArn { get; set; }

        public string region { get; set; }

        public string viewEndpoint { get; set; }

    }

    public class ObjectStoreServiceOptions
    {
        public string ObjectStoreUse { get; set; }
        public AliyunOSSOptions AliyunOSS { get; set; }
        public MinIOOptions MinIO { get; set; }

        public AWSOptions AWS { get; set; }

    }

    public class ObjectStoreDTO
    {
        public string ObjectStoreUse { get; set; }

        public AliyunOSSOptions AliyunOSS { get; set; }

        public MinIOOptions MinIO { get; set; }

        public AWSOptions AWS { get; set; }

    }

    public class AliyunOSSTempToken
    {
        public string AccessKeyId { get; set; }
        public string AccessKeySecret { get; set; }
        public string SecurityToken { get; set; }
        public string Expiration { get; set; }

        public string Region { get; set; }
        public string BucketName { get; set; }
        public string ViewEndpoint { get; set; }
    }



    public enum ObjectStoreUse
    {
        AliyunOSS = 0,
        MinIO = 1,
        AWS = 2,
    }

    public interface IOSSService
    {
        public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
        public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);

        public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);

        public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }

        public Task<string> GetSignedUrl(string ossRelativePath);

    }


    public class OSSService : IOSSService
    {
        public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }


        public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
        {
            ObjectStoreServiceOptions = options.CurrentValue;
        }

        /// <summary>
        ///  oosFolderPath  不要 "/ "开头   应该: TempFolder/ChildFolder
        /// </summary>
        /// <param name="fileStream"></param>
        /// <param name="oosFolderPath"></param>
        /// <param name="fileRealName"></param>
        /// <param name="isFileNameAddGuid"></param>
        /// <returns></returns>
        public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
        {
            var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
            //var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}";
            //var ossRelativePath = oosFolderPath + "/" + fileRealName;

            try
            {
                using (var memoryStream = new MemoryStream())
                {
                    fileStream.Seek(0, SeekOrigin.Begin);

                    fileStream.CopyTo(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);


                    if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
                    {
                        var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

                        var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);



                        // 上传文件
                        var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, memoryStream);

                    }
                    else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
                    {
                        var minIOConfig = ObjectStoreServiceOptions.MinIO;


                        var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
                            .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                            .Build();

                        var putObjectArgs = new PutObjectArgs()
                               .WithBucket(minIOConfig.bucketName)
                               .WithObject(ossRelativePath)
                               .WithStreamData(memoryStream)
                               .WithObjectSize(memoryStream.Length);

                        await minioClient.PutObjectAsync(putObjectArgs);
                    }
                    else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
                    {
                        var minIOConfig = ObjectStoreServiceOptions.AWS;


                        var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
                            .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                            .Build();

                        var putObjectArgs = new PutObjectArgs()
                               .WithBucket(minIOConfig.bucketName)
                               .WithObject(ossRelativePath)
                               .WithStreamData(memoryStream)
                               .WithObjectSize(memoryStream.Length);

                        await minioClient.PutObjectAsync(putObjectArgs);
                    }
                    else
                    {
                        throw new BusinessValidationFailedException("未定义的存储介质类型");
                    }
                }
            }
            catch (Exception ex)
            {

                throw new BusinessValidationFailedException($"上传发生异常:{ex.Message}");
            }




            return "/" + ossRelativePath;

        }



        /// <summary>
        /// oosFolderPath  不要 "/ "开头   应该: TempFolder/ChildFolder
        /// </summary>
        /// <param name="localFilePath"></param>
        /// <param name="oosFolderPath"></param>
        /// <returns></returns>
        /// <exception cref="BusinessValidationFailedException"></exception>
        public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
        {
            var localFileName = Path.GetFileName(localFilePath);

            var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";


            //var ossRelativePath = oosFolderPath + "/" + localFileName;


            if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
            {
                var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

                var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)? aliConfig.endPoint: aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);

                // 上传文件
                var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, localFilePath);

            }
            else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
            {
                var minIOConfig = ObjectStoreServiceOptions.MinIO;


                var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
                    .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                    .Build();

                var putObjectArgs = new PutObjectArgs()
                       .WithBucket(minIOConfig.bucketName)
                       .WithObject(ossRelativePath)
                       .WithFileName(localFilePath);

                await minioClient.PutObjectAsync(putObjectArgs);
            }
            else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
            {
                var minIOConfig = ObjectStoreServiceOptions.AWS;


                var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
                    .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                    .Build();

                var putObjectArgs = new PutObjectArgs()
                       .WithBucket(minIOConfig.bucketName)
                       .WithObject(ossRelativePath)
                       .WithFileName(localFilePath);

                await minioClient.PutObjectAsync(putObjectArgs);
            }
            else
            {
                throw new BusinessValidationFailedException("未定义的存储介质类型");
            }
            return "/" + ossRelativePath;

        }


        public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
        {

            ossRelativePath = ossRelativePath.TrimStart('/');
            try
            {


                if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
                {
                    var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

                    var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);

                    // 上传文件
                    var result = _ossClient.GetObject(aliConfig.bucketName, ossRelativePath);

                    // 将下载的文件流保存到本地文件
                    using (var fs = File.OpenWrite(localFilePath))
                    {
                        result.Content.CopyTo(fs);
                        fs.Close();
                    }

                }
                else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
                {
                    var minIOConfig = ObjectStoreServiceOptions.MinIO;

                    var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
                        .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                        .Build();

                    var getObjectArgs = new GetObjectArgs()
                    .WithBucket(minIOConfig.bucketName)
                    .WithObject(ossRelativePath)
                    .WithFile(localFilePath);

                    await minioClient.GetObjectAsync(getObjectArgs);

                }
                else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
                {
                    var minIOConfig = ObjectStoreServiceOptions.AWS;

                    var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
                        .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                        .Build();

                    var getObjectArgs = new GetObjectArgs()
                    .WithBucket(minIOConfig.bucketName)
                    .WithObject(ossRelativePath)
                    .WithFile(localFilePath);

                    await minioClient.GetObjectAsync(getObjectArgs);
                }
                else
                {
                    throw new BusinessValidationFailedException("未定义的存储介质类型");
                }
            }
            catch (Exception ex)
            {

                throw new BusinessValidationFailedException("oss下载失败!" + ex.Message);
            }





        }

        public async Task<string>  GetSignedUrl(string ossRelativePath)
        {
            ossRelativePath = ossRelativePath.TrimStart('/');
            try
            {


                if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
                {
                    var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

                    var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.endPoint : aliConfig.internalEndpoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);

                    // 生成签名URL。
                    var req = new GeneratePresignedUriRequest(aliConfig.bucketName, ossRelativePath, SignHttpMethod.Get)
                    {
                        // 设置签名URL过期时间,默认值为3600秒。
                        Expiration = DateTime.Now.AddHours(1),
                    };
                    var uri = _ossClient.GeneratePresignedUri(req);

                    return uri.PathAndQuery;

                }
                else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
                {
                    var minIOConfig = ObjectStoreServiceOptions.MinIO;

                    var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
                        .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                        .Build();


                    var args = new PresignedGetObjectArgs()
                        .WithBucket(minIOConfig.bucketName)
                        .WithObject(ossRelativePath)
                        .WithExpiry(3600)
                        /*.WithHeaders(reqParams)*/;

                    var presignedUrl = await minioClient.PresignedGetObjectAsync(args);

                    Uri uri = new Uri(presignedUrl);

                    string relativePath = uri.PathAndQuery;


                    return relativePath;

                }
                else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
                {
                    var minIOConfig = ObjectStoreServiceOptions.AWS;

                    var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
                        .WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
                        .Build();

                    var args = new PresignedGetObjectArgs()
                        .WithBucket(minIOConfig.bucketName)
                        .WithObject(ossRelativePath)
                        .WithExpiry(3600);

                    var presignedUrl = await minioClient.PresignedGetObjectAsync(args);

                    Uri uri = new Uri(presignedUrl);

                    string relativePath = uri.PathAndQuery;


                    return relativePath;
                }
                else
                {
                    throw new BusinessValidationFailedException("未定义的存储介质类型");
                }
            }
            catch (Exception ex)
            {

                throw new BusinessValidationFailedException("oss授权url失败!" + ex.Message);
            }

        }
    }


}