package com.yd.oss.service.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.utils.IpUtil;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.service.config.OssClientFactory;
import com.yd.oss.service.dto.FileMetadata;
import com.yd.oss.service.dto.OssUploadFileReqDto;
import com.yd.oss.service.dto.OssUploadFileResDto;
import com.yd.oss.service.dto.UploadResult;
import com.yd.oss.service.model.OssFile;
import com.yd.oss.service.model.OssOperationLog;
import com.yd.oss.service.model.OssProvider;
import com.yd.oss.service.service.IOssFileService;
import com.yd.oss.service.service.IOssProviderService;
import com.yd.oss.service.service.OssService;
import com.yd.oss.service.utils.FileUtil;
import com.yd.oss.service.utils.OssUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.time.Duration;
import java.util.Date;
import java.util.UUID;

@Service
@Primary
@Slf4j
public class AliYunOssServiceImpl implements OssService {

    @Autowired
    private IOssProviderService ossProviderService;

    @Autowired
    private IOssFileService ossFileService;

    @Autowired
    private OssClientFactory ossClientFactory;

    @Autowired
    private OssUtils ossUtils;

    // 默认提供商（用于没有传入项目ID或提供商ID的情况）
    private OssProvider getDefaultProvider() {
        return ossProviderService.getDefaultProvider();
    }

    /**
     * 上传文件
     * @param inputStream 文件流
     * @param fileName 原始文件名
     * @param bucketName OSS桶名
     * @param uploadUser 操作用户
     * @param type oss文件夹分类目录类型，例：如果是.xls那就是excel/
     * @param projectBizId 项目业务ID（用于确定OSS提供商）
     * @return
     */
    @Override
    public OssUploadFileResDto uploadFile(InputStream inputStream, String fileName,
                                          String bucketName, String uploadUser, String type, String projectBizId) {
        // 获取提供商
        OssProvider provider = ossProviderService.getProviderByProjectId(projectBizId);
        if (provider == null) {
            throw new BusinessException("未找到项目对应的OSS提供商，projectBizId=" + projectBizId);
        }

        OSS ossClient = null;
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            return doUploadFile(ossClient, provider, inputStream, fileName, bucketName, uploadUser, type, null, null, null, null, null, null);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 上传文件 - body入参方式（新，推荐）
     * @param file
     * @param reqDto
     * @return
     */
    @Override
    public OssUploadFileResDto uploadFileBody(MultipartFile file, OssUploadFileReqDto reqDto) {
        // 获取提供商
        OssProvider provider = ossProviderService.getProviderByProjectId(reqDto.getProjectBizId());
        if (provider == null) {
            throw new BusinessException("未找到项目对应的OSS提供商，projectBizId=" + reqDto.getProjectBizId());
        }

        OSS ossClient = null;
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            ossClient = ossClientFactory.createOssClient(provider);
            return doUploadFile(ossClient, provider, inputStream, file.getOriginalFilename(),
                    provider.getBucketName(), reqDto.getUploadUser(),
                    FileUtil.getFileType(file.getOriginalFilename()),
                    reqDto.getObjectBizId(), reqDto.getObjectName(),
                    reqDto.getObjectTableName(), reqDto.getObjectType(),
                    reqDto.getObjectBizId(), reqDto.getObjectName()); // 这里需要根据实际情况调整，原代码中存储了object信息
        } catch (IOException e) {
            log.error("文件输入流解析异常", e);
            throw new BusinessException("文件输入流解析异常");
        } finally {
            FileUtil.closeQuietly(inputStream);
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 上传文件（使用默认存储桶）
     * @param inputStream
     * @param fileName
     * @param uploadUser
     * @return
     */
    @Override
    public String uploadFile(InputStream inputStream, String fileName, String uploadUser) {
        // 使用默认提供商
        OssProvider defaultProvider = getDefaultProvider();
        OSS ossClient = null;
        try {
            ossClient = ossClientFactory.createOssClient(defaultProvider);
            OssUploadFileResDto result = doUploadFile(ossClient, defaultProvider, inputStream, fileName,
                    defaultProvider.getBucketName(), uploadUser, null, null, null, null, null, null, null);
            return result.getUrl();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 实际执行上传的逻辑（复用代码）
     */
    private OssUploadFileResDto doUploadFile(OSS ossClient, OssProvider provider,
                                             InputStream inputStream, String fileName,
                                             String bucketName, String uploadUser, String type,
                                             String objectBizId, String objectName,
                                             String objectTableName, String objectType,
                                             String creatorId, String creatorName) {
        long startTime = System.currentTimeMillis();
        String operationResult = "success";
        String errorMessage = null;
        OssFile ossFile = null;
        OssUploadFileResDto ossUploadFileDto = new OssUploadFileResDto();

        try {
            // 读取输入流到字节数组
            byte[] fileData = FileUtil.readInputStreamToBytes(inputStream);
            long fileSize = fileData.length;
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileData);

            // 生成文件key（这里使用ossUtils的方法，需要传入projectBizId，但此时provider已知，可根据需要调整）
            String fileKey = ossUtils.getFilePrefix(provider.getProjectBizId(), "", fileName, type);
            String actualBucket = StringUtils.isNotBlank(bucketName) ? bucketName : provider.getBucketName();
            String fileType = FileUtil.getFileType(fileName);

            // 创建上传请求
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileSize);
            metadata.setContentType(FileUtil.getContentType(fileType));

            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    actualBucket, fileKey, byteArrayInputStream, metadata);

            // 上传文件
            ossClient.putObject(putObjectRequest);

            // 创建文件记录
            ossFile = new OssFile();
            ossFile.setFileBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_OSS_FILE.getCode()));
            ossFile.setFileKey(fileKey);
            ossFile.setOriginalName(fileName);
            ossFile.setFileSize(fileSize);
            ossFile.setFileType(fileType);
            ossFile.setProviderBizId(provider.getProviderBizId());
            ossFile.setBucketName(actualBucket);
            ossFile.setUploadUser(uploadUser);
            ossFile.setObjectBizId(objectBizId);
            ossFile.setObjectName(objectName);
            ossFile.setObjectTableName(objectTableName);
            ossFile.setObjectType(objectType);
            // 获取当前登录用户信息（如果存在）
            AuthUserDto authUserDto = SecurityUtil.getCurrentLoginUser();
            if (authUserDto != null) {
                ossFile.setCreatorId(authUserDto.getUserBizId());
                ossFile.setCreatorName(authUserDto.getUsername());
            } else {
                ossFile.setCreatorId(creatorId);
                ossFile.setCreatorName(creatorName);
            }
            ossFileService.saveFileMetadata(ossFile);

            // 记录成功操作日志
            OssOperationLog operationLog = new OssOperationLog();
            operationLog.setFileBizId(ossFile.getFileBizId());
            operationLog.setOperationType("upload");
            operationLog.setOperationUser(uploadUser);
            operationLog.setOperationResult(operationResult);
            operationLog.setClientIp(IpUtil.getClientIp());
            operationLog.setCostTime(System.currentTimeMillis() - startTime);
            ossFileService.saveOperationLog(operationLog);

            log.info("文件上传成功: {} -> {}/{}", fileName, actualBucket, fileKey);

            ossUploadFileDto.setFileBizId(ossFile.getFileBizId());
            ossUploadFileDto.setFileKey(fileKey);
            ossUploadFileDto.setOriginalName(fileName);
            // 构建访问URL（根据实际需要，可以是公共读或预签名URL）
            String publicUrl = "https://" + actualBucket + "." + provider.getEndpoint() + "/" + fileKey;
            ossUploadFileDto.setUrl(publicUrl);
            ossUploadFileDto.setFileSize(fileSize);
            ossUploadFileDto.setFileType(fileType);
            return ossUploadFileDto;
        } catch (Exception e) {
            operationResult = "failure";
            errorMessage = e.getMessage();
            log.error("OSS上传文件失败: {}", fileName, e);
            throw new RuntimeException("OSS上传文件失败: " + fileName, e);
        } finally {
            // 记录失败日志（如果失败）
            if ("failure".equals(operationResult)) {
                OssOperationLog operationLog = new OssOperationLog();
                operationLog.setFileBizId(ossFile != null ? ossFile.getFileBizId() : "-1");
                operationLog.setOperationType("upload");
                operationLog.setOperationUser(uploadUser);
                operationLog.setOperationResult(operationResult);
                operationLog.setErrorMessage(errorMessage);
                operationLog.setClientIp(IpUtil.getClientIp());
                operationLog.setCostTime(System.currentTimeMillis() - startTime);
                ossFileService.saveOperationLog(operationLog);
            }
        }
    }

    /**
     * 下载文件
     * @param fileKey
     * @param bucketName
     * @return
     */
    @Override
    public InputStream downloadFile(String fileKey, String bucketName) {
        // 根据文件key获取提供商信息
        OssFile ossFile = ossFileService.getFileByKey(fileKey);
        if (ossFile == null) {
            throw new BusinessException("文件不存在: " + fileKey);
        }
        OssProvider provider = ossProviderService.getProviderByBizId(ossFile.getProviderBizId());
        if (provider == null) {
            throw new BusinessException("提供商不存在: " + ossFile.getProviderBizId());
        }

        OSS ossClient = null;
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            String actualBucket = StringUtils.isNotBlank(bucketName) ? bucketName : ossFile.getBucketName();

            OSSObject ossObject = ossClient.getObject(actualBucket, fileKey);
            InputStream inputStream = ossObject.getObjectContent();

            // 记录操作日志（成功）
            recordOperationLog(ossFile.getFileBizId(), "download", "system", "success", null, System.currentTimeMillis());

            log.info("文件下载成功: {}/{}", actualBucket, fileKey);
            // 注意：返回的InputStream需要由调用者负责关闭，但OSS客户端必须在此方法内关闭？
            // 不能关闭，因为流还未消费完。此处需要特殊处理：返回的流内部可能关联OSSClient，调用者使用后需主动关闭。
            // 一个解决方案是使用包装流，在close时同时关闭OSSClient。但为简化，这里不处理，要求调用者显式关闭。
            // 更好的做法是返回一个包装流，但需要改造。为了示例，我们保留原逻辑，但强调调用者需要关闭流并手动shutdown客户端。
            // 由于客户端不能在这里关闭，我们不得不将客户端保留到流消费完。这会导致资源泄漏。
            // 因此，建议将下载操作设计为直接返回字节数组或使用回调，或者使用预签名URL让客户端直接下载。
            // 这里为了演示，我们返回流，但客户端无法在这里关闭，存在风险。
            // 实际使用时，可考虑返回预签名URL或使用临时文件。
            // 此处暂时返回流，并记录警告。
            log.warn("返回原始InputStream，调用者必须确保在使用后关闭流，并注意OSSClient资源管理。");
            return inputStream;
        } catch (Exception e) {
            recordOperationLog(ossFile != null ? ossFile.getFileBizId() : "-1", "download", "system", "failure", e.getMessage(), System.currentTimeMillis());
            log.error("OSS下载文件失败: {}", fileKey, e);
            throw new RuntimeException("OSS下载文件失败: " + fileKey, e);
        } finally {
            // 注意：不能在这里shutdown，因为InputStream可能还未消费完。但如果不shutdown，客户端会一直保持连接。
            // 这是一个设计问题。实际生产环境建议使用预签名URL或临时文件下载。
        }
    }

    /**
     * 下载文件（使用默认存储桶）
     * @param fileKey
     * @return
     */
    @Override
    public InputStream downloadFile(String fileKey) {
        return downloadFile(fileKey, null);
    }

    /**
     * 删除文件
     * @param fileKey
     * @param bucketName
     * @param operator
     * @return
     */
    @Override
    public boolean deleteFile(String fileKey, String bucketName, String operator) {
        OssFile ossFile = ossFileService.getFileByKey(fileKey);
        if (ossFile == null) {
            throw new BusinessException("文件不存在: " + fileKey);
        }
        OssProvider provider = ossProviderService.getProviderByBizId(ossFile.getProviderBizId());
        if (provider == null) {
            throw new BusinessException("提供商不存在: " + ossFile.getProviderBizId());
        }

        OSS ossClient = null;
        long startTime = System.currentTimeMillis();
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            String actualBucket = StringUtils.isNotBlank(bucketName) ? bucketName : ossFile.getBucketName();

            ossClient.deleteObject(actualBucket, ossFile.getFileKey());
            ossFileService.markFileAsDeleted(fileKey);

            recordOperationLog(ossFile.getFileBizId(), "delete", operator, "success", null, startTime);
            log.info("文件删除成功: {}/{}", actualBucket, fileKey);
            return true;
        } catch (Exception e) {
            recordOperationLog(ossFile.getFileBizId(), "delete", operator, "failure", e.getMessage(), startTime);
            log.error("OSS删除文件失败: {}", fileKey, e);
            throw new RuntimeException("OSS删除文件失败: " + fileKey, e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    @Override
    public boolean deleteFileByBizId(String fileBizId, String operator) {
        OssFile ossFile = ossFileService.queryOne(fileBizId);
        if (ossFile == null) {
            throw new BusinessException("文件不存在: " + fileBizId);
        }
        OssProvider provider = ossProviderService.getProviderByBizId(ossFile.getProviderBizId());
        if (provider == null) {
            throw new BusinessException("提供商不存在: " + ossFile.getProviderBizId());
        }

        OSS ossClient = null;
        long startTime = System.currentTimeMillis();
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            ossClient.deleteObject(ossFile.getBucketName(), ossFile.getFileKey());
            ossFileService.removeById(ossFile.getId());

            recordOperationLog(ossFile.getFileBizId(), "delete", operator, "success", null, startTime);
            log.info("文件删除成功: {}/{}", ossFile.getBucketName(), ossFile.getFileKey());
            return true;
        } catch (Exception e) {
            recordOperationLog(ossFile.getFileBizId(), "delete", operator, "failure", e.getMessage(), startTime);
            log.error("删除文件失败: fileBizId={}", fileBizId, e);
            throw new RuntimeException("删除文件失败: " + fileBizId, e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 删除文件（使用默认存储桶）
     * @param fileKey
     * @param operator
     * @return
     */
    @Override
    public boolean deleteFile(String fileKey, String operator) {
        return deleteFile(fileKey, null, operator);
    }

    /**
     * 获取文件URL（预签名）
     * @param fileKey
     * @param bucketName
     * @param expiration
     * @return
     */
    @Override
    public String getFileUrl(String fileKey, String bucketName, Duration expiration) {
        OssFile ossFile = ossFileService.getFileByKey(fileKey);
        if (ossFile == null) {
            throw new BusinessException("文件不存在: " + fileKey);
        }
        OssProvider provider = ossProviderService.getProviderByBizId(ossFile.getProviderBizId());
        if (provider == null) {
            throw new BusinessException("提供商不存在: " + ossFile.getProviderBizId());
        }

        OSS ossClient = null;
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            String actualBucket = StringUtils.isNotBlank(bucketName) ? bucketName : ossFile.getBucketName();
            Date expirationDate = new Date(System.currentTimeMillis() + expiration.toMillis());
            URL url = ossClient.generatePresignedUrl(actualBucket, fileKey, expirationDate);
            return url.toString();
        } catch (Exception e) {
            log.error("获取文件URL失败: {}", fileKey, e);
            throw new RuntimeException("获取文件URL失败: " + fileKey, e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 获取文件URL（使用默认存储桶）
     * @param fileKey
     * @param expiration
     * @return
     */
    @Override
    public String getFileUrl(String fileKey, Duration expiration) {
        return getFileUrl(fileKey, null, expiration);
    }

    /**
     * 判断文件是否存在
     * @param fileKey
     * @param bucketName
     * @return
     */
    @Override
    public boolean doesFileExist(String fileKey, String bucketName) {
        OssFile ossFile = ossFileService.getFileByKey(fileKey);
        if (ossFile == null) {
            return false;
        }
        OssProvider provider = ossProviderService.getProviderByBizId(ossFile.getProviderBizId());
        if (provider == null) {
            return false;
        }

        OSS ossClient = null;
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            String actualBucket = StringUtils.isNotBlank(bucketName) ? bucketName : ossFile.getBucketName();
            return ossClient.doesObjectExist(actualBucket, fileKey);
        } catch (Exception e) {
            log.error("检查文件存在失败: {}", fileKey, e);
            return false;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 判断文件是否存在（使用默认存储桶）
     * @param fileKey
     * @return
     */
    @Override
    public boolean doesFileExist(String fileKey) {
        return doesFileExist(fileKey, null);
    }

    /**
     * 获取文件元数据
     * @param fileKey
     * @param bucketName
     * @return
     */
    @Override
    public FileMetadata getFileMetadata(String fileKey, String bucketName) {
        OssFile ossFile = ossFileService.getFileByKey(fileKey);
        if (ossFile == null) {
            throw new BusinessException("文件不存在: " + fileKey);
        }
        OssProvider provider = ossProviderService.getProviderByBizId(ossFile.getProviderBizId());
        if (provider == null) {
            throw new BusinessException("提供商不存在: " + ossFile.getProviderBizId());
        }

        OSS ossClient = null;
        try {
            ossClient = ossClientFactory.createOssClient(provider);
            String actualBucket = StringUtils.isNotBlank(bucketName) ? bucketName : ossFile.getBucketName();
            ObjectMetadata objectMetadata = ossClient.getObjectMetadata(actualBucket, fileKey);

            FileMetadata metadata = new FileMetadata();
            metadata.setFileKey(fileKey);
            metadata.setFileSize(objectMetadata.getContentLength());
            metadata.setContentType(objectMetadata.getContentType());
            metadata.setEtag(objectMetadata.getETag());
            // 如果有最后修改时间，可设置
            // metadata.setLastModified(objectMetadata.getLastModified());
            return metadata;
        } catch (Exception e) {
            log.error("获取文件元数据失败: {}", fileKey, e);
            throw new RuntimeException("获取文件元数据失败: " + fileKey, e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 获取文件元数据（使用默认存储桶）
     * @param fileKey
     * @return
     */
    @Override
    public FileMetadata getFileMetadata(String fileKey) {
        return getFileMetadata(fileKey, null);
    }

    /**
     * 切换OSS提供商-根据项目ID切换（已废弃，由每次操作动态决定，保留空实现）
     */
    @Override
    public void switchProviderByProjectId(String projectBizId) {
        // 不再需要
    }

    /**
     * 切换OSS提供商（已废弃）
     */
    @Override
    public void switchProvider(String providerName) {
        // 不再需要
    }

    /**
     * 切换OSS提供商（已废弃）
     */
    @Override
    public void switchProvider(Long providerId) {
        // 不再需要
    }

    /**
     * 获取当前使用的 OSS 客户端（已废弃，返回null）
     */
    @Override
    public OSS getOssClient() {
        return null;
    }

    /**
     * 获取当前使用的提供商（已废弃，返回默认提供商）
     */
    @Override
    public OssProvider getCurrentProvider() {
        return getDefaultProvider();
    }

    /**
     * 设置默认存储桶（已废弃）
     */
    @Override
    public void setDefaultBucket(String bucketName) {
        // 不再需要
    }

    /**
     * 获取默认存储桶（已废弃，返回默认提供商的桶）
     */
    @Override
    public String getDefaultBucket() {
        return getDefaultProvider().getBucketName();
    }

    /**
     * 获取上传结果
     */
    @Override
    public UploadResult getUploadResult(String fileKey, Duration expiration) {
        OssFile file = ossFileService.getFileByKey(fileKey);
        if (file == null) {
            throw new BusinessException("文件不存在: " + fileKey);
        }
        String accessUrl = getFileUrl(fileKey, expiration);
        String url = accessUrl.split("\\?")[0];

        UploadResult result = new UploadResult();
        result.setFileKey(fileKey);
        result.setAccessUrl(accessUrl);
        result.setUrl(url);
        result.setFileSize(file.getFileSize());
        result.setFileType(file.getFileType());
        result.setOriginalName(file.getOriginalName());
        result.setUploadTime(file.getUploadTime());
        return result;
    }

    /**
     * 上传字节数组并设置公共读
     */
    public String upload(byte[] content, String fileName,OSS ossClient, OssProvider provider) {
//        OssProvider defaultProvider = getDefaultProvider();
//        OSS ossClient = null;
        try {
//            ossClient = ossClientFactory.createOssClient(defaultProvider);
//            String objectName = "appointment/excel/" + UUID.randomUUID() + "/" + fileName;
            //扩展名
            String fileType = FileUtil.getFileType(fileName);
            //获取通用文件路径的前缀
            String filePrefix = ossUtils.getFilePrefix(provider.getProjectBizId(),"",fileName,fileType);
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    provider.getBucketName(), filePrefix, new ByteArrayInputStream(content));
            ossClient.putObject(putObjectRequest);
            ossClient.setObjectAcl(provider.getBucketName(), filePrefix, CannedAccessControlList.PublicRead);
            return "https://" + provider.getBucketName() + "." + provider.getEndpoint() + "/" + filePrefix;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 上传输入流并设置公共读
     */
    public String upload(InputStream inputStream, String fileName,OSS ossClient, OssProvider provider) {
//        OssProvider defaultProvider = getDefaultProvider();
//        OSS ossClient = null;
        try {
//            ossClient = ossClientFactory.createOssClient(defaultProvider);
//            String objectName = "appointment/excel/" + UUID.randomUUID() + "/" + fileName;
            //扩展名
            String fileType = FileUtil.getFileType(fileName);
            //获取通用文件路径的前缀
            String filePrefix = ossUtils.getFilePrefix(provider.getProjectBizId(),"",fileName,fileType);
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    provider.getBucketName(), filePrefix, inputStream);
            ossClient.putObject(putObjectRequest);
            ossClient.setObjectAcl(provider.getBucketName(), filePrefix, CannedAccessControlList.PublicRead);
            return "https://" + provider.getBucketName() + "." + provider.getEndpoint() + "/" + filePrefix;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 批量上传文件
     */
    @Override
    public com.yd.oss.feign.response.ApiBatchUploadResponse batchUploadFiles(
            java.util.List<MultipartFile> files, OssUploadFileReqDto reqDto) {
        com.yd.oss.feign.response.ApiBatchUploadResponse response = new com.yd.oss.feign.response.ApiBatchUploadResponse();
        java.util.List<com.yd.oss.feign.response.ApiUploadResponse> successFiles = new java.util.ArrayList<>();
        java.util.List<com.yd.oss.feign.response.ApiBatchUploadResponse.FailedFile> failedFiles = new java.util.ArrayList<>();

        if (files == null || files.isEmpty()) {
            response.setSuccessFiles(successFiles);
            response.setFailedFiles(failedFiles);
            response.setSuccessCount(0);
            response.setFailedCount(0);
            return response;
        }

        for (MultipartFile file : files) {
            try {
                OssUploadFileResDto uploadResult = uploadFileBody(file, reqDto);
                com.yd.oss.feign.response.ApiUploadResponse uploadResponse = new com.yd.oss.feign.response.ApiUploadResponse();
                uploadResponse.setFileBizId(uploadResult.getFileBizId());
                uploadResponse.setFileKey(uploadResult.getFileKey());
                uploadResponse.setOriginalName(uploadResult.getOriginalName());
                uploadResponse.setUrl(uploadResult.getUrl());
                uploadResponse.setFileSize(uploadResult.getFileSize());
                uploadResponse.setFileType(uploadResult.getFileType());
                successFiles.add(uploadResponse);
            } catch (Exception e) {
                log.error("批量上传文件失败: {}", file.getOriginalFilename(), e);
                com.yd.oss.feign.response.ApiBatchUploadResponse.FailedFile failedFile =
                        new com.yd.oss.feign.response.ApiBatchUploadResponse.FailedFile();
                failedFile.setFileName(file.getOriginalFilename());
                failedFile.setReason(e.getMessage());
                failedFiles.add(failedFile);
            }
        }

        response.setSuccessFiles(successFiles);
        response.setFailedFiles(failedFiles);
        response.setSuccessCount(successFiles.size());
        response.setFailedCount(failedFiles.size());
        log.info("批量上传完成: 成功{}个, 失败{}个", successFiles.size(), failedFiles.size());
        return response;
    }

    /**
     * 记录操作日志（公共方法）
     */
    private void recordOperationLog(String fileBizId, String operationType, String operator,
                                    String result, String errorMsg, long startTime) {
        OssOperationLog operationLog = new OssOperationLog();
        operationLog.setFileBizId(fileBizId);
        operationLog.setOperationType(operationType);
        operationLog.setOperationUser(operator);
        operationLog.setOperationResult(result);
        operationLog.setErrorMessage(errorMsg);
        operationLog.setClientIp(IpUtil.getClientIp());
        operationLog.setCostTime(System.currentTimeMillis() - startTime);
        ossFileService.saveOperationLog(operationLog);
    }
}