using Aliyun.OSS;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Minio.DataModel.Args;
using Minio;
using NPOI.HPSF;
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;

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 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;

            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(aliConfig.endPoint, 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("未定义的存储介质类型");
                }
            }


            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(aliConfig.endPoint, 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(aliConfig.endPoint, 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(aliConfig.endPoint, 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 reqParams = new Dictionary<string, string>(StringComparer.Ordinal)
                    //                {
                    //                    { "response-content-type", "application/json" }
                    //                };

                    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();

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

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

        }
    }


}
