using AlibabaCloud.SDK.Sts20150401;
using Aliyun.OSS;
using Aliyun.OSS.Common;
using Amazon;
using AlibabaCloud.SDK.Sts20150401;
using Aliyun.OSS;
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
using MassTransit;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel.Args;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using Minio.Exceptions;
using IRaCIS.Core.SCP.Service;
using Serilog;
using System.Web;
using IRaCIS.Core.Infrastructure.Extention;

namespace IRaCIS.Core.SCP;

#region 绑定和返回模型

[LowerCamelCaseJson]
public class MinIOOptions : AWSOptions
{
    public int Port { get; set; }

}


public class AWSOptions
{
    public string EndPoint { get; set; }
    public bool UseSSL { get; set; }
    public string AccessKeyId { get; set; }
    public string RoleArn { get; set; }
    public string SecretAccessKey { get; set; }
    public string BucketName { get; set; }
    public string ViewEndpoint { get; set; }
    public int DurationSeconds { get; set; }
    public string Region { 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 int DurationSeconds { get; set; }

    public string PreviewEndpoint { 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 bool IsOpenStoreSync { get; set; }

    public string ApiDeployRegion { get; set; }

    public List<SyncStoreConfig> SyncConfigList { get; set; } = new List<SyncStoreConfig>();

}

public class SyncStoreConfig
{
    public string Domain { get; set; }

    public string UploadRegion { get; set; }

    public string TargetRegion { get; set; }

    public string Primary { get; set; }

    public string Target { get; set; }

    public bool IsOpenSync { get; set; }

}

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


    public AliyunOSSTempToken AliyunOSS { get; set; }

    public MinIOOptions MinIO { get; set; }

    public AWSTempToken AWS { get; set; }

    public bool IsOpenStoreSync { get; set; }

    public List<SyncStoreConfig> SyncConfigList { get; set; }

}

[LowerCamelCaseJson]
public class AliyunOSSTempToken
{
    public string AccessKeyId { get; set; }
    public string AccessKeySecret { get; set; }

    public string EndPoint { get; set; }
    public string BucketName { get; set; }

    public string Region { get; set; }

    public string ViewEndpoint { get; set; }

    public string SecurityToken { get; set; }
    public DateTime Expiration { get; set; }

    public string PreviewEndpoint { get; set; }

    public string DownloadEndPoint => EndPoint.Insert(EndPoint.IndexOf("//") + 2, BucketName + ".");

}

[LowerCamelCaseJson]
public class AWSTempToken
{
    public string Region { get; set; }
    public string SessionToken { get; set; }
    public string EndPoint { get; set; }
    public string AccessKeyId { get; set; }
    public string SecretAccessKey { get; set; }
    public string BucketName { get; set; }
    public string ViewEndpoint { get; set; }
    public DateTime? Expiration { get; set; }
}

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


#endregion

// aws 参考链接 https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/S3/S3_Basics

public interface IOSSService
{
    public Task SetImmediateArchiveRule(string prefix, string ruleId = "immediate-archive", bool isDelete = false);
    public Task RestoreFilesByPrefixAsync(string prefix, int restoreDays = 3, int batchSize = 100);


    public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true, FileUploadRecordAddOrEdit? uploadInfo = null);
    public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true, bool randomFileName = false, FileUploadRecordAddOrEdit? uploadInfo = null);

    public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);

    public Task<Stream> GetStreamFromOSSAsync(string ossRelativePath);

    public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }

    public Task<string> GetSignedUrl(string ossRelativePath);

    public Task DeleteFromPrefix(string prefix, bool isCache = false);

    public Task DeleteObjects(List<string> objectKeys, bool isCache = false);

    List<string> GetRootFolderNames();

    public ObjectStoreDTO GetObjectStoreTempToken(string? domain = null, bool? isGetAllTempToken = null, string? objectUse = null);

    public Task MoveObject(string sourcePath, string destPath, bool overwrite = true);

    public Task<long> GetObjectSizeAsync(string sourcePath);

    public Task SyncFileAsync(string objectKey, ObjectStoreUse source, ObjectStoreUse destination, CancellationToken ct = default);
}


public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
                                  IFileUploadRecordService _fileUploadRecordService) : IOSSService
{
    public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; } = options.CurrentValue;

    private AliyunOSSTempToken AliyunOSSTempToken { get; set; }

    private AWSTempToken AWSTempToken { get; set; }




    /// <summary>
    /// 将指定前缀下的所有现有文件立即转为目标存储类型
    /// </summary>
    /// <param name="prefix">要转换的文件前缀，如 "project-a/logs/"</param>
    /// <param name="ruleId">规则ID，默认为"immediate-archive"</param>
    /// <param name="isDelete">默认是添加/更新 </param>
    public async Task SetImmediateArchiveRule(string prefix, string ruleId = "immediate-archive", bool isDelete = false)
    {

        BackBatchGetToken();

        if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
        {


            var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

            var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

            try
            {
                // 1. 先获取现有的所有生命周期规则（避免覆盖）
                var existingRules = new List<Aliyun.OSS.LifecycleRule>();
                try
                {
                    var existingRuleList = _ossClient.GetBucketLifecycle(aliConfig.BucketName);
                    if (existingRuleList != null)
                    {
                        existingRules.AddRange(existingRuleList);
                        Console.WriteLine($"找到 {existingRules.Count} 条现有规则");
                    }
                }
                catch (OssException ex) when (ex.ErrorCode == "NoSuchLifecycle")
                {
                    // 如果没有生命周期规则，继续创建新规则
                    Console.WriteLine("当前Bucket无生命周期规则，将创建新规则");
                }

                // 2. 创建立即生效的转换规则

                ruleId = $"{ruleId}_{prefix}";
                var immediateRule = new Aliyun.OSS.LifecycleRule
                {
                    ID = ruleId,
                    Prefix = prefix,
                    Status = RuleStatus.Enabled,
                    Transitions = new Aliyun.OSS.LifecycleRule.LifeCycleTransition[]
                        {
                        new Aliyun.OSS.LifecycleRule.LifeCycleTransition
                        {

                              LifeCycleExpiration =
                                {
                                    Days = 1
                                },
                            StorageClass = StorageClass.IA
                        },
                        new Aliyun.OSS.LifecycleRule.LifeCycleTransition
                        {

                              LifeCycleExpiration =
                                {
                                    Days = 30 //最后一次修改时间
                                },
                            StorageClass = StorageClass.Archive
                        }
                        }
                };




                // 3. 移除同名的旧规则（如果存在）
                existingRules.RemoveAll(r => r.ID == ruleId);

                // 4. 添加新规则到规则列表
                if (isDelete == false)
                {
                    existingRules.Add(immediateRule);

                }



                var request = new SetBucketLifecycleRequest(aliConfig.BucketName)
                {
                    LifecycleRules = existingRules
                };


                _ossClient.SetBucketLifecycle(request);


            }
            catch (OssException ex)
            {
                Log.Logger.Error($"❌ 设置失败 [错误码: {ex.ErrorCode}] 详细: {ex.Message}");

            }
            catch (Exception ex)
            {
                Log.Logger.Error($"❌ 发生未知错误: {ex.Message}");
            }
        }
        else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
        {
            var awsConfig = ObjectStoreServiceOptions.AWS;

            var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);



            //提供awsEndPoint（域名）进行访问配置
            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

            // 1. 获取现有的生命周期配置（避免覆盖）
            LifecycleConfiguration existingConfig = null;

            var getRequest = new GetLifecycleConfigurationRequest { BucketName = awsConfig.BucketName };
            var response = await amazonS3Client.GetLifecycleConfigurationAsync(getRequest);
            existingConfig = response.Configuration;
            Console.WriteLine($"找到 {existingConfig?.Rules?.Count ?? 0} 条现有规则");

            // 2. 生成唯一的规则ID
            ruleId = $"{ruleId}_{prefix.Replace('/', '_').Trim('_')}";

            // 3. 创建新的生命周期规则
            var immediateRule = new Amazon.S3.Model.LifecycleRule
            {
                Id = ruleId,
                Filter = new LifecycleFilter
                {
                    // 使用前缀筛选对象
                    LifecycleFilterPredicate = new LifecyclePrefixPredicate { Prefix = prefix }
                },
                Status = LifecycleRuleStatus.Enabled,
                // 定义多个转换阶段
                Transitions = new List<LifecycleTransition>
                {
                    // 1天后转为低频访问 (Standard-IA)
                    //new LifecycleTransition
                    //{
                    //    Days = 1, //Days' in Transition action must be greater than or equal to 30 for storageClass 'STANDARD_IA'"
                    //    StorageClass = S3StorageClass.StandardInfrequentAccess // 对应S3 Standard-IA
                    //},
                    // 30天后转为归档 (Glacier Instant Retrieval)
                    new LifecycleTransition
                    {
                        Days = 30, //创建时间
                        StorageClass = S3StorageClass.GlacierInstantRetrieval // 对应归档（即时检索）
                    }
                    // 如果需要更深的归档，可以继续添加：
                    // new LifecycleTransition { Days = 90, StorageClass = S3StorageClass.GlacierFlexibleRetrieval },
                    // new LifecycleTransition { Days = 180, StorageClass = S3StorageClass.DeepArchive }
                }
                // 注意：S3的生命周期规则不支持设置“立即生效（Days=0）”。
                // 如果要对存量文件立即生效，需要配合其他方法（如批量修改存储类型）。
            };

            // 4. 更新规则列表（移除同名旧规则，添加新规则）
            var existingRules = existingConfig.Rules ?? new List<Amazon.S3.Model.LifecycleRule>();
            existingRules.RemoveAll(r => r.Id == ruleId);

            if (isDelete == false)
            {
                existingRules.Add(immediateRule);

            }

            // 5. 提交新的生命周期配置
            var putRequest = new PutLifecycleConfigurationRequest
            {
                BucketName = awsConfig.BucketName,
                Configuration = new LifecycleConfiguration { Rules = existingRules }
            };

            await amazonS3Client.PutLifecycleConfigurationAsync(putRequest);

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

    /// 解冻指定前缀下的所有归档/冷归档文件
    /// </summary>
    /// <param name="prefix">要解冻的文件前缀</param>
    /// <param name="restoreDays">解冻后文件保持可读的天数（默认3天）</param>
    /// <param name="restoreTier">解冻优先级（仅AWS有效）</param>
    /// <param name="batchSize">批量处理大小（默认100）</param>
    public async Task RestoreFilesByPrefixAsync(string prefix, int restoreDays = 3, int batchSize = 100)
    {
        BackBatchGetToken();

        if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
        {
            var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
            var client = new OssClient(
                RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
                AliyunOSSTempToken.AccessKeyId,
                AliyunOSSTempToken.AccessKeySecret,
                AliyunOSSTempToken.SecurityToken
            );

            var bucketName = aliConfig.BucketName;
            int totalRestored = 0;
            int totalSkipped = 0;
            int totalFailed = 0;

            try
            {
                Console.WriteLine($"开始解冻阿里云OSS文件，前缀: {prefix}");

                var allObjects = new List<OssObjectSummary>();

                // 1. 分页列举文件
                string nextMarker = null;
                ObjectListing result = null;

                do
                {
                    var listRequest = new Aliyun.OSS.ListObjectsRequest(bucketName)
                    {
                        Prefix = prefix,
                        Marker = nextMarker,
                        MaxKeys = batchSize
                    };

                    result = client.ListObjects(listRequest);

                    allObjects.AddRange(result.ObjectSummaries);



                    nextMarker = result.NextMarker;

                } while (result.IsTruncated);

                // 2️⃣ 并行解冻（控制并发）
                Parallel.ForEach(
                    allObjects,
                    new ParallelOptions
                    {
                        MaxDegreeOfParallelism = 5 // ⭐ 推荐 5~10
                    },
                    obj =>
                    {
                        // 只处理归档
                        if (obj.StorageClass != StorageClass.Archive.ToString())
                        {
                            Interlocked.Increment(ref totalSkipped);
                            return;
                        }

                        try
                        {
                            var restoreRequest = new Aliyun.OSS.RestoreObjectRequest(bucketName, obj.Key)
                            {
                                Days = restoreDays
                            };

                            client.RestoreObject(restoreRequest);

                            Interlocked.Increment(ref totalRestored);
                            Console.WriteLine($"✅ 提交解冻: {obj.Key}");
                        }
                        catch (OssException ex) when (ex.ErrorCode == "RestoreAlreadyInProgress")
                        {
                            // 已在解冻中，算成功
                            Interlocked.Increment(ref totalSkipped);
                            Console.WriteLine($"⚠️ 已在解冻中: {obj.Key}");
                        }
                        catch (Exception ex)
                        {
                            Interlocked.Increment(ref totalFailed);
                            Console.WriteLine($"❌ 解冻失败: {obj.Key} - {ex.Message}");
                        }
                    }
                );

                // 3. 输出统计结果
                Console.WriteLine("\n================ 解冻完成 ================");
                Console.WriteLine($"总计处理: {totalRestored + totalSkipped + totalFailed} 个文件");
                Console.WriteLine($"成功解冻: {totalRestored} 个");
                Console.WriteLine($"跳过文件: {totalSkipped} 个 (非归档类型)");
                Console.WriteLine($"解冻失败: {totalFailed} 个");

                if (totalRestored > 0)
                {
                    Console.WriteLine($"\n📋 解冻说明:");
                    Console.WriteLine($"   • 解冻任务已提交，文件将在后台处理");
                    Console.WriteLine($"   • 解冻完成后，文件将保持可读状态 {restoreDays} 天");
                    Console.WriteLine($"   • 归档文件约需1分钟，冷归档需数小时");
                }
            }
            catch (Exception ex)
            {
                Log.Logger.Error($"❌ 阿里云解冻操作失败: {ex.Message}");
                throw;
            }
        }
        else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
        {
            var awsConfig = ObjectStoreServiceOptions.AWS;
            var credentials = new SessionAWSCredentials(
                AWSTempToken.AccessKeyId,
                AWSTempToken.SecretAccessKey,
                AWSTempToken.SessionToken
            );

            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            using var client = new AmazonS3Client(credentials, clientConfig);

            var bucketName = awsConfig.BucketName;
            int totalRestored = 0;
            int totalSkipped = 0;
            int totalFailed = 0;

            try
            {
                Console.WriteLine($"开始解冻AWS S3文件，前缀: {prefix}");

                var allObjects = new List<S3Object>();

                // 1. 分页列举文件
                string continuationToken = null;
                ListObjectsV2Response response = null;

                do
                {
                    var listRequest = new ListObjectsV2Request
                    {
                        BucketName = bucketName,
                        Prefix = prefix,
                        ContinuationToken = continuationToken,
                        MaxKeys = batchSize
                    };

                    response = await client.ListObjectsV2Async(listRequest);

                    allObjects.AddRange(response.S3Objects);


                    continuationToken = response.NextContinuationToken;

                } while (response.IsTruncated == true);

                // 2️⃣ 并行解冻（控制并发）
                await Parallel.ForEachAsync(
                       allObjects,
                       new ParallelOptions
                       {
                           MaxDegreeOfParallelism = 5 // ⭐ 推荐 5~10
                       },
                         async (obj, ct) =>
                         {
                             // 只处理归档
                             if (obj.StorageClass != S3StorageClass.Glacier)
                             {
                                 Interlocked.Increment(ref totalSkipped);
                                 return;
                             }

                             try
                             {
                                 var restoreRequest = new Amazon.S3.Model.RestoreObjectRequest
                                 {
                                     BucketName = bucketName,
                                     Key = obj.Key,
                                     Days = restoreDays,

                                 };

                                 await client.RestoreObjectAsync(restoreRequest);

                                 Interlocked.Increment(ref totalRestored);
                                 Console.WriteLine($"✅ 提交解冻: {obj.Key}");
                             }
                             catch (OssException ex) when (ex.ErrorCode == "RestoreAlreadyInProgress")
                             {
                                 // 已在解冻中，算成功
                                 Interlocked.Increment(ref totalSkipped);
                                 Console.WriteLine($"⚠️ 已在解冻中: {obj.Key}");
                             }
                             catch (Exception ex)
                             {
                                 Interlocked.Increment(ref totalFailed);
                                 Console.WriteLine($"❌ 解冻失败: {obj.Key} - {ex.Message}");
                             }
                         }
                   );

                // 3. 输出统计结果
                Console.WriteLine("\n================ 解冻完成 ================");
                Console.WriteLine($"总计处理: {totalRestored + totalSkipped + totalFailed} 个文件");
                Console.WriteLine($"成功解冻: {totalRestored} 个");
                Console.WriteLine($"跳过文件: {totalSkipped} 个 (非归档类型)");
                Console.WriteLine($"解冻失败: {totalFailed} 个");

                if (totalRestored > 0)
                {
                    Console.WriteLine($"\n📋 AWS解冻说明:");
                    Console.WriteLine($"   • 解冻任务已提交到Glacier服务");
                    Console.WriteLine($"   • 标准解冻: 3-5小时 (Glacier Flexible Retrieval)");
                    Console.WriteLine($"   • 加急解冻: 1-5分钟 (额外收费)");
                    Console.WriteLine($"   • 解冻后文件可读 {restoreDays} 天");
                }
            }
            catch (Exception ex)
            {
                Log.Logger.Error($"❌ AWS解冻操作失败: {ex.Message}");
                throw;
            }
        }
        else
        {
            throw new BusinessValidationFailedException("未定义的存储介质类型");
        }
    }


    /// <summary>
    /// 坑方法，会清空之前的规则
    /// </summary>
    /// <param name="prefix"></param>
    /// <param name="ruleId"></param>
    /// <returns></returns>
    /// <exception cref="BusinessValidationFailedException"></exception>
    public async Task SetLifecycle(string prefix, string ruleId = "immediate-archive")
    {
        BackBatchGetToken();

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

            var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

            ruleId = $"{ruleId}_{prefix}";
            var rule = new Aliyun.OSS.LifecycleRule
            {
                ID = ruleId,
                Prefix = prefix,
                Status = RuleStatus.Enabled,
                Transitions = new Aliyun.OSS.LifecycleRule.LifeCycleTransition[]
                        {
                        new Aliyun.OSS.LifecycleRule.LifeCycleTransition
                        {

                              LifeCycleExpiration =
                                {
                                    Days = 1
                                },
                            StorageClass = StorageClass.IA
                        },
                        new Aliyun.OSS.LifecycleRule.LifeCycleTransition
                        {

                              LifeCycleExpiration =
                                {
                                    Days = 30
                                },
                            StorageClass = StorageClass.Archive
                        }
                        }
            };


            //会清空之前历史的规则，不能用。。。
            var request = new SetBucketLifecycleRequest(aliConfig.BucketName);
            request.AddLifecycleRule(rule);

            _ossClient.SetBucketLifecycle(request);


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

            var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);



            //提供awsEndPoint（域名）进行访问配置
            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            var amazonS3Client = new AmazonS3Client(credentials, clientConfig);


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




    /// <summary>
    ///  oosFolderPath  不要 "/ "开头   应该： TempFolder/ChildFolder
    /// </summary>
    /// <param name="fileStream"></param>
    /// <param name="oosFolderPath"></param>
    /// <param name="fileRealName"></param>
    /// <param name="isFileNameAddGuid"></param>
    /// <param name="uploadInfo">  只用赋值业务参数Id 和批次信息即可，其他信息不用传递</param>
    /// <returns></returns>
    public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true, FileUploadRecordAddOrEdit? uploadInfo = null)
    {
        BackBatchGetToken();

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

        try
        {
            if (fileStream.CanSeek)
                fileStream.Seek(0, SeekOrigin.Begin);


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

                var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);



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

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


                var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                    .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
                    .Build();

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

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

                var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);



                //提供awsEndPoint（域名）进行访问配置
                var clientConfig = new AmazonS3Config
                {
                    RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                    //,UseHttp = true,
                };

                var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

                var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
                {
                    BucketName = awsConfig.BucketName,
                    InputStream = fileStream,
                    Key = ossRelativePath,
                };

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

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


        var returnPath = "/" + ossRelativePath;


        if (ObjectStoreServiceOptions.IsOpenStoreSync && uploadInfo != null)
        {
            var fileType = Path.GetExtension(returnPath).TrimStart('.');

            uploadInfo.FileSize = fileStream.CanSeek ? fileStream.Length : 0;
            uploadInfo.Path = returnPath;
            uploadInfo.FileName = fileRealName;
            uploadInfo.FileType = fileType.IsNullOrEmpty()?"dcm": fileType;


            await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo);
        }


        return returnPath;

    }



    //后端批量上传 或者下载，不每个文件获取临时token
    private void BackBatchGetToken()
    {
        if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
        {
            if (AliyunOSSTempToken == null)
            {
                GetObjectStoreTempToken();
            }
            //token 过期了
            if (AliyunOSSTempToken?.Expiration.AddSeconds(10) <= DateTime.Now)
            {
                GetObjectStoreTempToken();
            }


        }
        else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
        {
            if (AWSTempToken == null)
            {
                GetObjectStoreTempToken();
            }
            //token 过期了
            if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
            {
                GetObjectStoreTempToken();
            }
        }
    }


    /// <summary>
    /// oosFolderPath  不要 "/ "开头   应该： TempFolder/ChildFolder
    /// </summary>
    /// <param name="localFilePath"></param>
    /// <param name="oosFolderPath"></param>
    /// <param name="isFileNameAddGuid"></param>
    /// <param name="randomFileName">随机文件名</param>
    /// <returns></returns>
    /// <exception cref="BusinessValidationFailedException"></exception>
    public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true, bool randomFileName = false, FileUploadRecordAddOrEdit? uploadInfo = null)
    {
        BackBatchGetToken();

        long fileSize = 0;

        var localFileName = Path.GetFileName(localFilePath);

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

        if (randomFileName)
        {
            var fileExtension = localFileName.Split(".").LastOrDefault();
            ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}.{fileExtension}";
        }

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

            var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

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

            fileSize = result.ContentLength;

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


            var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
                .Build();

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

            var result = await minioClient.PutObjectAsync(putObjectArgs);

            fileSize = result.Size;
        }
        else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
        {
            var awsConfig = ObjectStoreServiceOptions.AWS;

            // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
            var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

            //提供awsEndPoint（域名）进行访问配置
            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

            var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
            {
                BucketName = awsConfig.BucketName,
                FilePath = localFilePath,
                Key = ossRelativePath,
            };

            var result = await amazonS3Client.PutObjectAsync(putObjectRequest);
            fileSize = result.ContentLength;
        }
        else
        {
            throw new BusinessValidationFailedException("未定义的存储介质类型");
        }

        var returnPath = "/" + ossRelativePath;


        if (ObjectStoreServiceOptions.IsOpenStoreSync && uploadInfo != null)
        {

            var fileType = Path.GetExtension(returnPath).TrimStart('.');

            uploadInfo.FileSize = fileSize;
            uploadInfo.Path = returnPath;
            uploadInfo.FileName = Path.GetFileName(localFilePath);
            uploadInfo.FileType = fileType.IsNullOrEmpty() ? "dcm" : fileType;



            await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo);
        }


        return returnPath;

    }


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

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


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

                var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

                var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);

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

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

                var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                    .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).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 awsConfig = ObjectStoreServiceOptions.AWS;

                // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
                var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

                //提供awsEndPoint（域名）进行访问配置
                var clientConfig = new AmazonS3Config
                {
                    RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                    //,UseHttp = true,
                };

                var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

                var getObjectArgs = new Amazon.S3.Model.GetObjectRequest()
                {
                    BucketName = awsConfig.BucketName,
                    Key = ossRelativePath,
                };


                await (await amazonS3Client.GetObjectAsync(getObjectArgs)).WriteResponseStreamToFileAsync(localFilePath, true, CancellationToken.None);


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

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





    }

    public async Task<Stream> GetStreamFromOSSAsync(string ossRelativePath)
    {
        BackBatchGetToken();
        ossRelativePath = ossRelativePath.TrimStart('/');

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

                var _ossClient = new OssClient(
                    RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
                    AliyunOSSTempToken.AccessKeyId,
                    AliyunOSSTempToken.AccessKeySecret,
                    AliyunOSSTempToken.SecurityToken
                );

                var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);

                // 直接返回流
                return result.Content;

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

                var minioClient = new MinioClient()
                    .WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                    .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
                    .WithSSL(minIOConfig.UseSSL)
                    .Build();

                var pipe = new System.IO.Pipelines.Pipe();

                _ = Task.Run(async () =>
                {
                    try
                    {
                        var args = new GetObjectArgs()
                            .WithBucket(minIOConfig.BucketName)
                            .WithObject(ossRelativePath)
                            .WithCallbackStream(stream =>
                            {
                                stream.CopyTo(pipe.Writer.AsStream());
                            });

                        await minioClient.GetObjectAsync(args);
                        await pipe.Writer.CompleteAsync();
                    }
                    catch (Exception ex)
                    {
                        await pipe.Writer.CompleteAsync(ex);
                    }
                });

                return pipe.Reader.AsStream();
            }
            else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
            {
                var awsConfig = ObjectStoreServiceOptions.AWS;

                var credentials = new SessionAWSCredentials(
                    AWSTempToken.AccessKeyId,
                    AWSTempToken.SecretAccessKey,
                    AWSTempToken.SessionToken
                );

                var clientConfig = new AmazonS3Config
                {
                    RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                    //,UseHttp = true,
                };

                var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

                var getObjectRequest = new Amazon.S3.Model.GetObjectRequest
                {
                    BucketName = awsConfig.BucketName,
                    Key = ossRelativePath
                };

                var response = await amazonS3Client.GetObjectAsync(getObjectRequest);

                // ⭐ 直接返回流
                return response.ResponseStream;

            }
            else
            {
                throw new BusinessValidationFailedException("未定义的存储介质类型");
            }
        }
        catch (Exception ex)
        {
            throw new BusinessValidationFailedException("oss流获取失败! " + ex.Message);
        }
    }


    public async Task<string> GetSignedUrl(string ossRelativePath)
    {
        GetObjectStoreTempToken();

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


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

                var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

                // 生成签名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.AccessKeyId, minIOConfig.SecretAccessKey).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 awsConfig = ObjectStoreServiceOptions.AWS;


                // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
                var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

                //提供awsEndPoint（域名）进行访问配置
                var clientConfig = new AmazonS3Config
                {
                    RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                    //,UseHttp = true,
                };

                var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

                var presignedUrl = await amazonS3Client.GetPreSignedURLAsync(new GetPreSignedUrlRequest()
                {
                    BucketName = awsConfig.BucketName,
                    Key = ossRelativePath,
                    Expires = DateTime.UtcNow.AddMinutes(120)
                });

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

    }


    /// <summary>
    /// 移动OSS文件到新路径
    /// </summary>
    /// <param name="sourcePath">原文件路径（格式：bucket/key）</param>
    /// <param name="destPath">新文件路径（格式：bucket/key）</param>
    /// <param name="overwrite">是否覆盖已存在的目标文件（默认true）</param>
    public async Task MoveObject(string sourcePath, string destPath, bool overwrite = true)
    {
        GetObjectStoreTempToken();

        switch (ObjectStoreServiceOptions.ObjectStoreUse)
        {
            case "AliyunOSS":
                #region 阿里云
                var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
                var client = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
                if (sourcePath.StartsWith("/"))
                {
                    sourcePath = sourcePath.Substring(1);
                }


                if (destPath.StartsWith("/"))
                {
                    destPath = destPath.Substring(1);
                }

                var sourceBucket = aliConfig.BucketName;
                var sourceKey = sourcePath;

                var destBucket = aliConfig.BucketName;

                var destKey = destPath;


                try
                {
                    // 检查目标是否存在（当不允许覆盖时）
                    if (!overwrite && client.DoesObjectExist(destBucket, destKey))
                    {
                        throw new InvalidOperationException("File Exist");
                    }


                    //var copyRequest = new Aliyun.OSS.CopyObjectRequest(sourceBucket, sourceKey, sourceBucket, destKey);
                    //var result = client.CopyObject(copyRequest);

                    //// 2. 删除原文件（可选，根据是否需要保留原文件）
                    //client.DeleteObject(sourceBucket, sourceKey);

                    // 执行复制
                    var copyRequestAli = new Aliyun.OSS.CopyObjectRequest(
                        sourceBucket, sourceKey,
                        destBucket, destKey);

                    // 保持原文件元数据
                    copyRequestAli.NewObjectMetadata = new ObjectMetadata
                    {
                        ContentType = client.GetObjectMetadata(sourceBucket, sourceKey).ContentType
                    };

                    var result = client.CopyObject(copyRequestAli);

                    // 删除原文件（仅在复制成功后）
                    client.DeleteObject(sourceBucket, sourceKey);
                }
                catch (OssException ex)
                {
                    throw new Exception($"[{ex.ErrorCode}] {ex.Message}", ex);
                }
                #endregion

                break;
            case "MinIO":
                #region MinIO
                var minIOConfig = ObjectStoreServiceOptions.MinIO;
                var minioClient = new MinioClient()
                 .WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                 .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
                 .WithSSL(minIOConfig.UseSSL)
                 .Build();

                // 定义源路径和目标路径
                string destinationKey = "b路径/文件名";

                try
                {
                    // 1. 复制文件到新路径[2,5](@ref)
                    using (var memoryStream = new MemoryStream())
                    {
                        // 下载源文件流
                        await minioClient.GetObjectAsync(new GetObjectArgs()
                            .WithBucket(minIOConfig.BucketName)
                            .WithObject(sourcePath)
                            .WithCallbackStream(stream => stream.CopyTo(memoryStream)));

                        memoryStream.Position = 0; // 重置流位置

                        // 上传到新路径
                        await minioClient.PutObjectAsync(new PutObjectArgs()
                            .WithBucket(minIOConfig.BucketName)
                            .WithObject(destinationKey)
                            .WithStreamData(memoryStream)
                            .WithObjectSize(memoryStream.Length));
                    }

                    // 2. 删除原文件[1,6](@ref)
                    await minioClient.RemoveObjectAsync(new RemoveObjectArgs()
                        .WithBucket(minIOConfig.BucketName)
                        .WithObject(sourcePath));
                }
                catch (MinioException ex)
                {
                    // 处理异常（例如：记录日志或抛出）
                    throw new Exception();
                }
                #endregion

                break;
            case "AWS":
                #region AWS
                var awsConfig = ObjectStoreServiceOptions.AWS;

                var credentials = new SessionAWSCredentials(
                    AWSTempToken.AccessKeyId,
                    AWSTempToken.SecretAccessKey,
                    AWSTempToken.SessionToken
                );

                var clientConfig = new AmazonS3Config
                {
                    RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                    //,UseHttp = true,
                };

                var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

                // 定义原路径和目标路径


                // 1. 复制对象到新路径
                var copyRequest = new Amazon.S3.Model.CopyObjectRequest
                {
                    SourceBucket = awsConfig.BucketName,
                    SourceKey = sourcePath,
                    DestinationBucket = awsConfig.BucketName,
                    DestinationKey = destPath
                };

                try
                {
                    // 执行复制操作
                    await amazonS3Client.CopyObjectAsync(copyRequest);

                    // 2. 删除原对象
                    var deleteRequest = new Amazon.S3.Model.DeleteObjectRequest
                    {
                        BucketName = awsConfig.BucketName,
                        Key = sourcePath
                    };
                    await amazonS3Client.DeleteObjectAsync(deleteRequest);


                }
                catch (AmazonS3Exception ex)
                {
                    Console.WriteLine($"ERROR: {ex.Message}");
                    // 可根据异常类型细化处理（如文件不存在、权限问题等）
                }
                #endregion
                break;
            default:
                throw new BusinessValidationFailedException("ERROR");

        }

    }

    /// <summary>
    /// 获取所有根目录名称
    /// </summary>
    /// <returns></returns>
    public List<string> GetRootFolderNames()
    {
        GetObjectStoreTempToken();
        var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
        var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
                                        AliyunOSSTempToken.AccessKeyId,
                                        AliyunOSSTempToken.AccessKeySecret,
                                        AliyunOSSTempToken.SecurityToken);

        List<string> rootFolders = new List<string>();
        string nextMarker = null;

        try
        {
            ObjectListing objectListing = null;
            do
            {
                // 列出根目录下的对象和文件夹
                objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
                {

                    MaxKeys = 1000,
                    Marker = nextMarker,
                    Delimiter = "/"  // 使用分隔符来模拟文件夹
                });

                // 遍历 CommonPrefixes 获取根文件夹名称
                foreach (var prefix in objectListing.CommonPrefixes)
                {
                    rootFolders.Add(prefix.TrimEnd('/')); // 去掉末尾的斜杠
                }

                // 设置 NextMarker 以获取下一页的数据
                nextMarker = objectListing.NextMarker;

            } while (objectListing.IsTruncated);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }

        return rootFolders;
    }

    /// <summary>
    /// 删除某个目录的文件 (包含单个文件，oss单个文件需要去除前缀/)
    /// </summary>
    /// <param name="prefix"></param>
    /// <returns></returns>
    public async Task DeleteFromPrefix(string prefix, bool isCache = false)
    {

        //打开了同步的，删除的时候，一起删除
        if (ObjectStoreServiceOptions.IsOpenStoreSync && ObjectStoreServiceOptions.SyncConfigList.Any(t => t.IsOpenSync))
        {
            foreach (var config in ObjectStoreServiceOptions.SyncConfigList.Where(t => t.IsOpenSync))
            {
                ObjectStoreServiceOptions.ObjectStoreUse = config.Primary;

                GetObjectStoreTempToken();

                await DeleteFromPrefixInternal(prefix, isCache);
            }
        }
        else
        {
            GetObjectStoreTempToken();

            await DeleteFromPrefixInternal(prefix, isCache);
        }

    }


    private async Task DeleteFromPrefixInternal(string prefix, bool isCache = false)
    {
        if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
        {
            var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

            var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

            var bucketName = string.Empty;

            if (isCache)
            {
                Uri uri = new Uri(aliConfig.ViewEndpoint);
                string host = uri.Host; // 获取 "zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com"
                string[] parts = host.Split('.');
                bucketName = parts[0];
            }
            else
            {
                bucketName = aliConfig.BucketName;
            }



            try
            {
                ObjectListing objectListing = null;
                string nextMarker = null;
                do
                {
                    // 使用 prefix 模拟目录结构，设置 MaxKeys 和 NextMarker
                    objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(bucketName)
                    {
                        Prefix = prefix,
                        MaxKeys = 1000,
                        Marker = nextMarker
                    });

                    List<string> keys = objectListing.ObjectSummaries.Select(t => t.Key).ToList();

                    // 删除获取到的文件
                    if (keys.Count > 0)
                    {
                        _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(bucketName, keys, false));
                    }

                    // 设置 NextMarker 以获取下一页的数据
                    nextMarker = objectListing.NextMarker;

                } while (objectListing.IsTruncated);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }


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


            var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
                .Build();


            var listArgs = new ListObjectsArgs().WithBucket(minIOConfig.BucketName).WithPrefix(prefix).WithRecursive(true);



            // 创建一个空列表用于存储对象键
            var objects = new List<string>();

            // 使用 await foreach 来异步迭代对象列表
            await foreach (var item in minioClient.ListObjectsEnumAsync(listArgs))
            {
                objects.Add(item.Key);
            }


            if (objects.Count > 0)
            {
                var objArgs = new RemoveObjectsArgs()
              .WithBucket(minIOConfig.BucketName)
              .WithObjects(objects);

                // 删除对象
                await minioClient.RemoveObjectsAsync(objArgs);
            }



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

            var awsConfig = ObjectStoreServiceOptions.AWS;

            // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
            var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

            //提供awsEndPoint（域名）进行访问配置
            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

            // 列出指定前缀下的所有对象
            var listObjectsRequest = new ListObjectsV2Request
            {
                BucketName = awsConfig.BucketName,
                Prefix = prefix
            };

            var listObjectsResponse = await amazonS3Client.ListObjectsV2Async(listObjectsRequest);

            if (listObjectsResponse.S3Objects?.Count > 0)
            {
                // 准备删除请求
                var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
                {
                    BucketName = awsConfig.BucketName,
                    Objects = new List<KeyVersion>()
                };

                foreach (var s3Object in listObjectsResponse.S3Objects)
                {
                    deleteObjectsRequest.Objects.Add(new KeyVersion
                    {
                        Key = s3Object.Key
                    });
                }

                // 批量删除对象
                var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
            }



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


    public async Task DeleteObjects(List<string> objectKeys, bool isCache = false)
    {
        //打开了同步的，删除的时候，一起删除
        if (ObjectStoreServiceOptions.IsOpenStoreSync && ObjectStoreServiceOptions.SyncConfigList.Any(t => t.IsOpenSync))
        {
            foreach (var config in ObjectStoreServiceOptions.SyncConfigList.Where(t => t.IsOpenSync))
            {
                ObjectStoreServiceOptions.ObjectStoreUse = config.Primary;

                GetObjectStoreTempToken();

                await DeleteObjectsInternal(objectKeys, isCache);
            }
        }
        else
        {
            GetObjectStoreTempToken();

            await DeleteObjectsInternal(objectKeys, isCache);
        }
    }
    public async Task DeleteObjectsInternal(List<string> objectKeys, bool isCache = false)
    {


        GetObjectStoreTempToken();

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

            var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

            var bucketName = string.Empty;

            if (isCache)
            {
                Uri uri = new Uri(aliConfig.ViewEndpoint);
                string host = uri.Host; // 获取 "zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com"
                string[] parts = host.Split('.');
                bucketName = parts[0];
            }
            else
            {
                bucketName = aliConfig.BucketName;
            }

            if (objectKeys.Count > 0)
            {
                var result = _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(bucketName, objectKeys, false));

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


            var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
            .Build();


            if (objectKeys.Count > 0)
            {
                var objArgs = new RemoveObjectsArgs()
              .WithBucket(minIOConfig.BucketName)
              .WithObjects(objectKeys);

                // 删除对象
                await minioClient.RemoveObjectsAsync(objArgs);
            }
        }
        else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
        {

            var awsConfig = ObjectStoreServiceOptions.AWS;


            // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
            var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

            //提供awsEndPoint（域名）进行访问配置
            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

            if (objectKeys.Count > 0)
            {
                // 准备删除请求
                var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
                {
                    BucketName = awsConfig.BucketName,
                    Objects = objectKeys.Select(t => new KeyVersion() { Key = t }).ToList()
                };


                // 批量删除对象
                var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
            }

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

    public async Task<long> GetObjectSizeAsync(string sourcePath)
    {
        BackBatchGetToken();


        var objectkey = sourcePath.Trim('/');

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

            var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

            var key = HttpUtility.UrlDecode(objectkey);
            var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, key);

            long fileSize = metadata?.ContentLength ?? 0; // 文件大小（字节）

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


            var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
                .WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
            .Build();


            var stat = await minioClient.StatObjectAsync(new Minio.DataModel.Args.StatObjectArgs()
                 .WithBucket(minIOConfig.BucketName)
                 .WithObject(objectkey));

            return stat.Size; // 文件大小（字节）
        }
        else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
        {

            var awsConfig = ObjectStoreServiceOptions.AWS;


            // 提供awsAccessKeyId和awsSecretAccessKey构造凭证
            var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

            //提供awsEndPoint（域名）进行访问配置
            var clientConfig = new AmazonS3Config
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
                //,UseHttp = true,
            };

            var request = new Amazon.S3.Model.GetObjectMetadataRequest
            {
                BucketName = awsConfig.BucketName,
                Key = objectkey
            };

            var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

            var response = await amazonS3Client.GetObjectMetadataAsync(request);

            long fileSize = response.ContentLength; // 文件大小（字节）

            return fileSize;

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



    public ObjectStoreDTO GetObjectStoreTempToken(string? domain = null, bool? isGetAllTempToken = null, string? objectUse = null)
    {
        string objectStoreUse = string.Empty;
        //使用指定配置
        if (objectUse != null)
        {
            objectStoreUse = objectUse?.Trim() ?? string.Empty;
        }
        //根据域名动态判断
        else
        {
            //如果传递了域名，并且打开了存储同步，根据域名使用的具体存储覆盖之前的配置，否则就用固定的配置
            if (ObjectStoreServiceOptions.IsOpenStoreSync && domain.IsNotNullOrEmpty() && ObjectStoreServiceOptions.SyncConfigList.Any(t => t.Domain == domain))
            {

                var find = ObjectStoreServiceOptions.SyncConfigList.FirstOrDefault(t => t.Domain == domain);
                if (find != null)
                {
                    objectStoreUse = find.Primary;
                }

            }
            else
            {
                //兜底，如果是本地测试环境，那就使用部署默认配置
                objectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse;
            }
        }


        var objectStoreDTO = new ObjectStoreDTO() { ObjectStoreUse = objectStoreUse, IsOpenStoreSync = ObjectStoreServiceOptions.IsOpenStoreSync, SyncConfigList = ObjectStoreServiceOptions.SyncConfigList };

        if (objectStoreUse == "AliyunOSS" || isGetAllTempToken == true)
        {
            var ossOptions = ObjectStoreServiceOptions.AliyunOSS;

            var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
            {
                AccessKeyId = ossOptions.AccessKeyId,
                AccessKeySecret = ossOptions.AccessKeySecret,
                //AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8",
                //AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa",

                Endpoint = "sts.cn-hangzhou.aliyuncs.com"
            });

            var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
            // 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称，例如oss-role-session。
            assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
            // 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
            assumeRoleRequest.RoleArn = ossOptions.RoleArn;
            //assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
            assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
            var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
            var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
            var credentials = response.Body.Credentials;

            var tempToken = new AliyunOSSTempToken()
            {
                AccessKeyId = credentials.AccessKeyId,
                AccessKeySecret = credentials.AccessKeySecret,

                //转为服务器时区，最后统一转为客户端时区
                Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
                SecurityToken = credentials.SecurityToken,


                Region = ossOptions.Region,
                BucketName = ossOptions.BucketName,
                EndPoint = ossOptions.EndPoint,
                ViewEndpoint = ossOptions.ViewEndpoint,
                PreviewEndpoint = ossOptions.PreviewEndpoint

            };

            AliyunOSSTempToken = tempToken;

            objectStoreDTO.AliyunOSS = tempToken;

        }
        if (objectStoreUse == "MinIO")
        {
            objectStoreDTO.MinIO = ObjectStoreServiceOptions.MinIO;
        }
        if (objectStoreUse == "AWS" || isGetAllTempToken == true)
        {
            var awsOptions = ObjectStoreServiceOptions.AWS;


            // 创建 STS 客户端（考虑使用 RegionEndpoint）
            var stsConfig = new AmazonSecurityTokenServiceConfig
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(awsOptions.Region)
            };

            //aws 临时凭证
            // 创建 STS 客户端
            var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey, stsConfig);

            // 使用 AssumeRole 请求临时凭证
            var assumeRoleRequest = new AssumeRoleRequest
            {

                RoleArn = awsOptions.RoleArn, // 角色 ARN
                RoleSessionName = $"session-name-{NewId.NextGuid()}",
                DurationSeconds = awsOptions.DurationSeconds          // 临时凭证有效期
            };

            var assumeRoleResponse = stsClient.AssumeRoleAsync(assumeRoleRequest).Result;

            var credentials = assumeRoleResponse.Credentials;

            var tempToken = new AWSTempToken()
            {
                AccessKeyId = credentials.AccessKeyId,
                SecretAccessKey = credentials.SecretAccessKey,
                SessionToken = credentials.SessionToken,
                Expiration = credentials.Expiration,
                Region = awsOptions.Region,
                BucketName = awsOptions.BucketName,
                EndPoint = awsOptions.EndPoint,
                ViewEndpoint = awsOptions.ViewEndpoint,

            };

            AWSTempToken = tempToken;

            objectStoreDTO.AWS = tempToken;
        }

        if (objectStoreUse.IsNullOrEmpty())
        {
            throw new BusinessValidationFailedException("未定义的存储介质类型");
        }

        return objectStoreDTO;
    }


    public async Task SyncFileAsync(string objectKey, ObjectStoreUse source, ObjectStoreUse destination, CancellationToken ct = default)
    {
        var tempConfig = GetObjectStoreTempToken(isGetAllTempToken: true);


        var aliConfig = ObjectStoreServiceOptions.AliyunOSS;

        var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);

        var awsConfig = ObjectStoreServiceOptions.AWS;

        var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);

        //提供awsEndPoint（域名）进行访问配置
        var clientConfig = new AmazonS3Config
        {
            RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
        };

        var amazonS3Client = new AmazonS3Client(credentials, clientConfig);

        // ⭐ 关键变量
        IDisposable? owner = null;
        Stream sourceStream;
        long contentLength;

        // ========= 获取流 + 长度 =========
        switch (source)
        {
            case ObjectStoreUse.AliyunOSS:
                {

                    var obj = _ossClient.GetObject(
                        aliConfig.BucketName,
                        objectKey);

                    owner = obj;
                    sourceStream = obj.Content;
                    contentLength = obj.ContentLength;
                    break;
                }

            case ObjectStoreUse.AWS:
                {
                    var response = await amazonS3Client.GetObjectAsync(
                        awsConfig.BucketName,
                        objectKey,
                        ct);

                    owner = response;
                    sourceStream = response.ResponseStream;
                    contentLength = response.Headers.ContentLength;
                    break;
                }

            default:
                throw new BusinessValidationFailedException("未定义的同步类型");
        }

        try
        {
            // ========= 上传 =========
            if (destination == ObjectStoreUse.AWS)
            {
                var putRequest = new Amazon.S3.Model.PutObjectRequest
                {
                    BucketName = awsConfig.BucketName,
                    Key = objectKey,
                    InputStream = sourceStream,
                    Headers = { ContentLength = contentLength }
                };

                await amazonS3Client.PutObjectAsync(putRequest, ct);
            }
            else if (destination == ObjectStoreUse.AliyunOSS)
            {
                _ossClient.PutObject(
                    aliConfig.BucketName,
                    objectKey,
                    sourceStream);
            }
            else
            {
                throw new BusinessValidationFailedException("未定义的同步类型");
            }
        }
        finally
        {
            // ⭐⭐⭐ 真正释放 HTTP 连接
            owner?.Dispose();
        }
    }

}
