using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Auth.Sts;
using Aliyun.Acs.Core.Profile;
using Aliyun.OSS;
using Aliyun.OSS.Common;
using CSRedis;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using QYZH.InteractiveMagazine.Common.Extensions;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using System.Text.Json;
using System.Web;

namespace QYZH.InteractiveMagazine.Infrastructure.OSS
{
    public class OssService
    {
        private readonly OssClient _ossClient;
        private readonly OSSOptions _ossOption;
        private readonly CSRedisClient _redis;
        private readonly ILogger<OssService> _logger;
        //private readonly IOssResourceRepository _ossResourceRepository;
        public OssService(IOptionsMonitor<OSSOptions> options, CSRedisClient redis, ILogger<OssService> logger)
        {
            // _ossOption = configuration.GetSection("AliyunOSSConfigs").Get<OSSOptions>();
            _ossOption = options.CurrentValue;
            _ossClient = new OssClient($"oss-cn-{_ossOption.Region}.aliyuncs.com", _ossOption.AccessKeyID, _ossOption.AccessKeySecret);
            _ossClient.SetRegion($"cn-{_ossOption.Region}");
            _redis = redis;
            _logger = logger;
            //_ossResourceRepository = ossResourceRepository;
        }

        public async Task<OssCredentials> GetSTSTokenAsync(CancellationToken cancellationToken)
        {
            var stsJson = await _redis.GetAsync("STS-InteractiveMagazine-OssCredentials");
            if (string.IsNullOrWhiteSpace(stsJson))
            {
                // ststoken
                IClientProfile profile = DefaultProfile.GetProfile($"oss-cn-{_ossOption.Region}", _ossOption.AccessKeyID, _ossOption.AccessKeySecret);
                DefaultAcsClient client = new DefaultAcsClient(profile);

                var policy = new
                {
                    Version = "1",
                    Statement = new List<dynamic>
                    {
                        new
                        {
                            Action = new List<string> { "oss:PutObject", "oss:GetObject","oss:DeleteObject" },
                            Resource = new List<string> { $"acs:oss:*:*:{_ossOption.BucketName}/temp/*" },
                            //Condition = new 
                            //{
                            //   NumericLessThanEquals = new Dictionary<string, object>()
                            //   {
                            //       {"oss:ContentLength",104857600 }
                            //   }
                            //},
                            Effect = "Allow",
                        }
                    }
                };


                var assumeRoleRequest = new AssumeRoleRequest();
                assumeRoleRequest.Policy = JsonSerializer.Serialize(policy);
                assumeRoleRequest.RoleArn = _ossOption.RoleArn;
                assumeRoleRequest.RoleSessionName = "oss-services";//这里的名字随便写
                assumeRoleRequest.DurationSeconds = 3600;//过期时间
                var response = client.GetAcsResponse(assumeRoleRequest);

                var expiration = DateTime.Parse(response.Credentials.Expiration).AddMinutes(5);
                var result = new OssCredentials
                {
                    AccessKeyId = response.Credentials.AccessKeyId,
                    AccessKeySecret = response.Credentials.AccessKeySecret,
                    SecurityToken = response.Credentials.SecurityToken,
                    ExpireTime = expiration.ToMillisecondsTimestamp(),
                    BucketName = _ossOption.BucketName,
                    Region = $"oss-cn-{_ossOption.Region}",
                    Domain = _ossOption.Domain
                };

                await _redis.SetAsync("STS-InteractiveMagazine-OssCredentials", result, expiration - DateTime.Now);
                return result;
            }
            else
            {
                return JsonSerializer.Deserialize<OssCredentials>(stsJson);
            }
        }

        public async Task<Dictionary<string, string>> GetSTSToken()
        {
            var stsJson = await _redis.GetAsync("QYZH.InteractiveMagazine.STS");
            if (stsJson.IsNull())
            {
                // ststoken
                IClientProfile profile = DefaultProfile.GetProfile($"oss-cn-{_ossOption.Region}", _ossOption.AccessKeyID, _ossOption.AccessKeySecret);
                DefaultAcsClient client = new DefaultAcsClient(profile);

                var policy = new
                {
                    Version = "1",
                    Statement = new List<dynamic>
                    {
                        new
                        {
                            Action = new List<string> { "oss:PutObject", "oss:GetObject","oss:DeleteObject" },
                            Resource = new List<string> { $"acs:oss:*:*:{_ossOption.BucketName}/temp/*" },
                            //Condition = new 
                            //{
                            //   NumericLessThanEquals = new Dictionary<string, object>()
                            //   {
                            //       {"oss:ContentLength",104857600 }
                            //   }
                            //},
                            Effect = "Allow",
                        }
                    }
                };


                var request = new AssumeRoleRequest();
                request.Policy = JsonSerializer.Serialize(policy);
                request.RoleArn = _ossOption.RoleArn;
                request.RoleSessionName = "oss-services";//这里的名字随便写
                request.DurationSeconds = 3600;//过期时间
                var response = client.GetAcsResponse(request);

                var expiration = DateTime.Parse(response.Credentials.Expiration);
                var result = new Dictionary<string, string>
                {
                    {"AccessKeyId", response.Credentials.AccessKeyId},
                    {"AccessKeySecret",response.Credentials.AccessKeySecret },
                    {"SecurityToken",response.Credentials.SecurityToken },
                    {"Expiration", DateTime.Parse(response.Credentials.Expiration).ToString("yyyy-MM-dd HH:mm:ss") },
                    {"BucketName",_ossOption.BucketName },
                    {"Region",$"oss-cn-{_ossOption.Region }"},
                    {"Domain",_ossOption.Domain }
                };

                var seconds = (expiration - DateTime.Now).TotalSeconds - 300;
                await _redis.SetAsync("QYZH.InteractiveMagazine.STS", result, TimeSpan.FromSeconds(seconds));
                return result;
            }
            return JsonSerializer.Deserialize<Dictionary<string, string>>(stsJson);
        }

        /// <summary>
        /// 上传单个
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string PutObject(string key, Stream content)
        {
            //try
            //{
            var result = _ossClient.PutObject(_ossOption.BucketName, key, content);
            if (result.HttpStatusCode == System.Net.HttpStatusCode.OK)
            {
                return key;
            }
            else return null;
            //}
            //catch (Exception ex)
            //{
            //    return null;
            //}
        }

        /// <summary>
        /// 删除单个
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteObject(string key)
        {
            try
            {

                if (key.IsNull()) return false;

                key = HttpUtility.UrlDecode(key);
                //_ossResourceRepository.UpdateDiy.Set(s => s.Status, -1).Where(w => w.Path == key).ExecuteAffrows();

                var result = _ossClient.DeleteObject(_ossOption.BucketName, key);
                return result.HttpStatusCode == System.Net.HttpStatusCode.OK;
            }
            catch (OssException ex)
            {
                _logger.LogError(ex.Message + ex.StackTrace);
                return false;
            }
        }

        /// <summary>
        /// 判断对象是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DoesObjectExist(string key)
        {
            try
            {
                if (key.IsNull()) return false;

                key = key.RemoveDomain();
                key = HttpUtility.UrlDecode(key);

                return _ossClient.DoesObjectExist(_ossOption.BucketName, key);
            }
            catch (OssException ex)
            {
                _logger.LogError(ex.Message + ex.StackTrace);
                return false;
            }
        }

        /// <summary>
        /// 获取对象内容流
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public Stream? GetObjectStream(string key)
        {
            try
            {
                if (key.IsNull()) return null;

                key = key.RemoveDomain();
                key = HttpUtility.UrlDecode(key);

                var ossObject = _ossClient.GetObject(_ossOption.BucketName, key);
                return ossObject.Content;
            }
            catch (OssException ex)
            {
                _logger.LogError(ex.Message + ex.StackTrace);
                return null;
            }
        }

        /// <summary>
        /// 删除多个
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public bool DeleteObjects(List<string>? keys)
        {
            try
            {
                if (keys.IsNull()) return false;

                // 设置为详细模式，返回所有删除的文件列表。
                var quietMode = false;

                keys = keys.Select(it => it.RemoveDomain()).ToList();

                //_ossResourceRepository.UpdateDiy.Set(s => s.Status, -1).Where(w => keys.Contains(w.Path)).ExecuteAffrows();

                var request = new DeleteObjectsRequest(_ossOption.BucketName, keys, quietMode);
                // 删除多个文件。
                var result = _ossClient.DeleteObjects(request);


                //var del = _ossResourceRepository.Delete(w => keys.Contains(w.Path));
                //BusinessException.ThrowIf(!del, "删除资源失败");


                return result.Keys.Count() == keys.Count;
            }
            catch (OssException ex)
            {
                _logger.LogError(ex.Message + ex.StackTrace);
                return false;
            }
        }


        public List<string> ListObjects(string prefix)
        {
            try
            {
                var keys = new List<string>();
                ObjectListing result = null;
                string nextMarker = string.Empty;
                do
                {
                    var listObjectsRequest = new ListObjectsRequest(_ossOption.BucketName)
                    {
                        Marker = nextMarker,
                        MaxKeys = 100,
                        Prefix = prefix,
                    };
                    result = _ossClient.ListObjects(listObjectsRequest);
                    foreach (var summary in result.ObjectSummaries)
                    {
                        keys.Add(summary.Key);
                    }
                    nextMarker = result.NextMarker;
                } while (result.IsTruncated);
                return keys;
            }
            catch (OssException ex)
            {
                _logger.LogError(ex.Message + ex.StackTrace);
                return null;
            }
        }

        /// <summary>
        /// 复制文件
        /// </summary>
        /// <param name="sourceObject"></param>
        /// <param name="targetObject"></param>
        /// <returns></returns>
        public bool CopyObject(string sourceObject, string targetObject, long? id = null)
        {
            try
            {
                //var metadata = new ObjectMetadata();
                // 设置自定义元数据。自定义元数据为键值对（Key-Value）的形式，例如Key为mk1，Value为mv1。
                //metadata.AddHeader("mk1", "mv1");
                //metadata.AddHeader("mk2", "mv2");
                sourceObject = sourceObject.RemoveDomain();
                sourceObject = Uri.UnescapeDataString(sourceObject);

                //var uow = _unitOfWorkManager.Begin();
                //var data = _ossResourceRepository.Insert(new OssResource
                //{
                //    MainId = id,
                //    SoucePath = sourceObject,
                //    Path = targetObject,

                //});
                //BusinessException.ThrowIf(data.IsNull(), "资源添加失败");

                var req = new CopyObjectRequest(_ossOption.BucketName, sourceObject, _ossOption.BucketName, targetObject)
                {
                    // 如果NewObjectMetadata为null则为COPY模式（即拷贝源文件的元数据），非null则为REPLACE模式（覆盖源文件的元数据）。
                    NewObjectMetadata = null
                };
                var result = _ossClient.CopyObject(req);
                return result.HttpStatusCode == System.Net.HttpStatusCode.OK;
            }
            catch (OssException ex)
            {
                _logger.LogError(ex.Message + ex.StackTrace);
                return false;
            }

        }
    }
}
