package com.rj.service.impl;

import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisParam;
import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.utils.Constants;
import com.alibaba.dashscope.utils.JsonUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.controller.TextModelController;
import com.rj.entity.ImageModel;
import com.rj.mapper.ImageModelMapper;
import com.rj.service.IImageModelService;
import com.rj.service.MinIOService;
import com.rj.config.AliyunConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;

/**
 * 图像模型服务实现类
 * 
 * 实现IImageModelService接口中定义的所有业务方法。
 * 该类负责处理图像模型相关的业务逻辑，包括：
 * - 图像模型记录的保存、查询、更新、删除操作
 * - 根据各种条件查询图像模型记录
 * - 异常处理和日志记录
 * 
 * 继承ServiceImpl获得MyBatis-Plus提供的基础CRUD能力，
 * 同时实现自定义的业务方法。
 * 
 * @author 系统生成
 * @date 2025/1/30
 * @version 1.0
 */
@Slf4j
@Service
public class ImageModelServiceImpl extends ServiceImpl<ImageModelMapper, ImageModel> 
        implements IImageModelService {

    @Autowired
    private MinIOService minIOService;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Autowired
    private AliyunConfig aliyunConfig;

    /**
     * 保存图像模型记录
     * 
     * 将图像模型数据保存到数据库中，包含完整的异常处理和日志记录。
     * 该方法会记录操作开始、成功或失败的日志信息。
     * 
     * @param imageModel 图像模型记录对象，包含所有必要的字段信息
     * @return 是否保存成功，true表示保存成功，false表示保存失败
     */
    @Override
    public boolean saveImageModel(ImageModel imageModel) {
        try {
            log.info("保存图像模型记录开始，参数：{}", imageModel);
            boolean result = this.save(imageModel);
            if (result) {
                log.info("图像模型记录保存成功，ID: {}", imageModel.getUuid());
            } else {
                log.error("图像模型记录保存失败");
            }
            return result;
        } catch (Exception e) {
            log.error("保存图像模型记录异常", e);
            return false;
        }
    }

    /**
     * 根据UUID查询图像模型记录
     * 
     * 通过唯一标识符查询对应的图像模型记录。
     * 使用LambdaQueryWrapper构建查询条件，确保类型安全。
     * 
     * @param uuid 唯一标识符，对应数据库主键
     * @return 图像模型记录，如果未找到则返回null
     */
    @Override
    public ImageModel getByUuid(String uuid) {
        try {
            LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ImageModel::getUuid, uuid);
            return this.getOne(queryWrapper);
        } catch (Exception e) {
            log.error("根据ID查询图像模型记录异常", e);
            return null;
        }
    }

    /**
     * 根据请求ID查询图像模型记录
     * 
     * 通过请求ID查询对应的图像模型记录。
     * 由于一个请求ID可能对应多条记录，此方法返回最新的一条。
     * 查询结果按创建时间降序排列，取第一条记录。
     * 
     * @param requestId 请求ID，用于追踪处理请求
     * @return 图像模型记录，如果未找到则返回null
     */
    @Override
    public ImageModel getByRequestId(String requestId) {
        try {
            LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ImageModel::getRequestId, requestId)
                       .orderByDesc(ImageModel::getCreateTime)
                       .last("LIMIT 1");
            return this.getOne(queryWrapper);
        } catch (Exception e) {
            log.error("根据请求ID查询图像模型记录异常", e);
            return null;
        }
    }

    /**
     * 根据任务ID查询图像模型记录
     * 
     * 通过任务ID查询对应的图像模型记录。
     * 由于一个任务ID可能对应多条记录，此方法返回最新的一条。
     * 查询结果按创建时间降序排列，取第一条记录。
     * 
     * @param taskId 任务ID，用于追踪异步处理任务
     * @return 图像模型记录，如果未找到则返回null
     */
    @Override
    public ImageModel getByTaskId(String taskId) {
        try {
            LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ImageModel::getTaskId, taskId)
                       .orderByDesc(ImageModel::getCreateTime)
                       .last("LIMIT 1");
            return this.getOne(queryWrapper);
        } catch (Exception e) {
            log.error("根据任务ID查询图像模型记录异常", e);
            return null;
        }
    }

    /**
     * 根据所属人电话查询图像模型记录
     * 
     * 通过所属人电话查询对应的图像模型记录。
     * 由于一个电话号码可能对应多条记录，此方法返回最新的一条。
     * 查询结果按创建时间降序排列，取第一条记录。
     * 
     * @param ownerPhone 所属人电话，用于查询特定用户的记录
     * @return 图像模型记录，如果未找到则返回null
     */
    @Override
    public ImageModel getByOwnerPhone(String ownerPhone) {
        try {
            LambdaQueryWrapper<ImageModel> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ImageModel::getOwnerPhone, ownerPhone)
                       .orderByDesc(ImageModel::getCreateTime)
                       .last("LIMIT 1");
            return this.getOne(queryWrapper);
        } catch (Exception e) {
            log.error("根据所属人电话查询图像模型记录异常", e);
            return null;
        }
    }

    /**
     * 去除图像中的中英文字符或常见水印
     * 
     * 实现图像水印去除的核心业务逻辑，包括：
     * 1. 参数验证和预处理
     * 2. 调用AI模型进行水印检测和去除
     * 3. 处理结果并生成访问URL
     * 4. 保存处理记录到数据库
     * 5. 返回处理结果
     * 
     * @param imageModel 图像模型记录对象，包含处理参数和结果信息
     * @return 处理后的图像模型记录，包含结果URL等信息
     */
    @Override
    public ImageModel removeWatermar(ImageModel imageModel) {
        try {
            log.info("开始去除图像水印，参数：{}", imageModel);
            
            // 1. 参数验证
            if (imageModel.getMaterialTempUrl() == null || imageModel.getMaterialTempUrl().trim().isEmpty()) {
                log.error("素材URL不能为空");
                throw new IllegalArgumentException("素材URL不能为空");
            }
            imageModel.setPrompt("去除图像中的文字");
            imageModel.setModelName("wanx2.1-imageedit");
            imageModel.setFunctionName("remove_watermark");
            // 3. 模拟AI模型处理（实际项目中这里会调用真实的AI服务）
            log.info("调用AI模型进行水印去除处理...");
            /**
             * {
             *   "input": {
             *     "function": "remove_watermark",
             *     "prompt": "去除图像中的文字",
             *     "base_image_url": "http://wanx.alicdn.com/material/20250318/remove_watermark_1.png"
             *   }
             * }
             */
// 若没有配置环境变量，请用百炼API Key将下行替换为：apiKey="sk-xxx"
              String apiKey = System.getenv("DASHSCOPE_API_KEY");
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("prompt_extend", true);

            ImageSynthesisParam param =
                    ImageSynthesisParam.builder()
                            .apiKey(apiKey)
                            .model(imageModel.getModelName())
                            .function(imageModel.getFunctionName())
                            .prompt(imageModel.getPrompt())
                            .baseImageUrl(imageModel.getMaterialTempUrl().trim())
                            .n(1)
                            .size("1024*1024")
                            .parameters(parameters)
                            .build();

            ImageSynthesis imageSynthesis = new ImageSynthesis();
            ImageSynthesisResult result = null;
            try {
                System.out.println("---sync call, please wait a moment----");
                log.info("开始同步调用,参数是：{} ",param);
                result = imageSynthesis.call(param);
                log.info("返回结果 ： ", result);
                System.out.println(JsonUtils.toJson(result));


                result.getOutput().getResults().forEach(resultItem -> {

                    imageModel.setResultImageUrl(resultItem.get("url"));
                });
            } catch (ApiException | NoApiKeyException e){
                 log.error("api call error", e);
            }
            System.out.println(JsonUtils.toJson(result));

            // 4. 下载AI处理结果图片并上传到MinIO
            if (result != null && result.getOutput() != null && !result.getOutput().getResults().isEmpty()) {
                String resultImageUrl = result.getOutput().getResults().get(0).get("url");
                if (resultImageUrl != null && !resultImageUrl.trim().isEmpty()) {
                    log.info("开始下载AI处理结果图片: {}", resultImageUrl);
                    
                    try {
                        // 下载图片到字节数组
                        byte[] imageBytes = downloadImageToBytes(resultImageUrl);
                        log.info("图片下载成功，大小: {} bytes", imageBytes.length);
                        
                        // 生成唯一文件名
                        String resultFileName = generateUniqueFileName("jpg");
                        
                        // 上传到MinIO
                        String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/jpeg");
                        log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
                        
                        // 生成7天临时访问链接
                        String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
                        log.info("生成7天临时访问链接: {}", resultImageTempUrl);
                        
                        // 更新ImageModel对象
                        imageModel.setResultImageUrl(resultImageMinIOUrl);
                        imageModel.setResultImageTempUrl(resultImageTempUrl);
                        
                    } catch (Exception e) {
                        log.error("下载或上传AI处理结果图片失败", e);
                        throw new RuntimeException("处理结果图片失败: " + e.getMessage(), e);
                    }
                } else {
                    log.warn("AI处理结果中没有有效的图片URL");
                }
            } else {
                log.warn("AI处理结果为空或无效");
            }

            imageModel.setImageType("remove_water");
            // 6. 保存处理记录
            boolean saveResult = this.updateById(imageModel);
            if (!saveResult) {
                log.error("保存水印去除记录失败");
                throw new RuntimeException("保存水印去除记录失败");
            }
            
            log.info("水印去除处理完成，ID: {}, 结果URL: {}", 
                    imageModel.getUuid(), imageModel.getResultImageTempUrl());
            
            return imageModel;
            
        } catch (Exception e) {
            log.error("去除图像水印异常", e);
            throw new RuntimeException("去除图像水印失败: " + e.getMessage(), e);
        }
    }

    /**
     * 上传图片素材
     * 
     * 实现图片素材上传的完整业务逻辑，包括：
     * 1. 文件验证和格式检查（根据阿里云参数要求）
     * 2. 上传到MinIO存储
     * 3. 生成永久URL和临时URL
     * 4. 保存上传记录到数据库
     * 
     * @param file 上传的图片文件
     * @param ownerName 所属人姓名
     * @param ownerPhone 所属人电话
     * @param imageType 图片类型（base_image主体图像 或 ref_image引导图像）
     * @param imageName 图像名称
     * @return 图像模型记录，包含上传结果和URL信息
     */
    @Override
    public ImageModel uploadImageMaterial(MultipartFile file, String ownerName, String ownerPhone, String imageType, String imageName) {
        try {
            log.info("开始上传图片素材，文件名：{}，所属人：{}，电话：{}，图像类型：{}", 
                    file.getOriginalFilename(), ownerName, ownerPhone, imageType);
            
            // 1. 文件验证（根据阿里云参数要求）
            validateImageFile(file, imageType);
            
            // 2. 生成唯一文件名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = getFileExtension(originalFilename);
            String uniqueFileName = generateUniqueFileName(fileExtension);
            
            // 3. 上传到MinIO
            log.info("开始上传文件到MinIO，文件名：{}", uniqueFileName);
            String materialUrl = minIOService.uploadFileWithName(file, uniqueFileName);
            String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
            
            // 4. 构建图像模型记录
            ImageModel imageModel = new ImageModel();
            imageModel.setImageName(originalFilename);
            imageModel.setOwnerName(ownerName);
            imageModel.setOwnerPhone(ownerPhone);
            imageModel.setImageType(imageType);
            imageModel.setMaterialUrl(materialUrl);
            imageModel.setMaterialTempUrl(materialTempUrl);
            imageModel.setCreateTime(LocalDateTime.now());
            imageModel.setUpdateTime(LocalDateTime.now());

            if (imageName != null && !imageName.trim().isEmpty()) {
                imageModel.setImageName(imageName);
            }
            
            // 5. 保存到数据库
            boolean saveResult = this.saveImageModel(imageModel);
            if (!saveResult) {
                log.error("保存图片素材上传记录失败");
                throw new RuntimeException("保存图片素材上传记录失败");
            }
            
            log.info("图片素材上传成功，ID: {}，永久URL: {}，临时URL: {}", 
                    imageModel.getUuid(), materialUrl, materialTempUrl);
            
            return imageModel;
            
        } catch (Exception e) {
            log.error("上传图片素材异常", e);
            throw new RuntimeException("上传图片素材失败: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean removeByUuid(String uuid) {
        boolean b = this.removeById(uuid);
        return b;
    }

    /**
     * 上传引导图像
     * 
     * 专门用于上传引导图像的方法，自动转换为带透明背景的RGBA四通道图像
     * 如果上传的图像不是RGBA格式，系统会自动转换为RGBA格式
     * 
     * @param file 上传的引导图像文件
     * @param ownerName 所属人姓名
     * @param ownerPhone 所属人电话
     * @param imageName 图像名称
     * @return 图像模型记录，包含上传结果和URL信息
     */
    @Override
    public ImageModel uploadRefImage(MultipartFile file, String ownerName, String ownerPhone, String imageName) {
        try {
            log.info("开始上传引导图像，文件名：{}，所属人：{}，电话：{}", 
                    file.getOriginalFilename(), ownerName, ownerPhone);
            
            // 1. 基础文件验证（不限制格式，因为会自动转换）
            validateBasicImageFile(file);
            
            // 2. 转换为RGBA格式
            log.info("开始转换图像为RGBA格式");
            byte[] rgbaImageBytes = convertToRGBA(file);
            log.info("图像转换完成，RGBA格式大小: {} bytes", rgbaImageBytes.length);
            
            // 3. 生成唯一文件名（固定为PNG格式）
            String uniqueFileName = generateUniqueFileName("png");
            
            // 4. 上传转换后的RGBA图像到MinIO
            log.info("开始上传转换后的RGBA图像到MinIO，文件名：{}", uniqueFileName);
            String materialUrl = minIOService.uploadFile(rgbaImageBytes, uniqueFileName, "image/png");
            String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
            
            // 5. 构建图像模型记录
            ImageModel imageModel = new ImageModel();
            imageModel.setImageName(file.getOriginalFilename());
            imageModel.setOwnerName(ownerName);
            imageModel.setOwnerPhone(ownerPhone);
            imageModel.setImageType("ref_image"); // 设置为引导图像类型
            imageModel.setMaterialUrl(materialUrl);
            imageModel.setMaterialTempUrl(materialTempUrl);
            imageModel.setCreateTime(LocalDateTime.now());
            imageModel.setUpdateTime(LocalDateTime.now());

            if (imageName != null && !imageName.trim().isEmpty()) {
                imageModel.setImageName(imageName);
            }
            
            // 6. 保存到数据库
            boolean saveResult = this.saveImageModel(imageModel);
            if (!saveResult) {
                log.error("保存引导图像上传记录失败");
                throw new RuntimeException("保存引导图像上传记录失败");
            }
            
            log.info("引导图像上传成功，已转换为RGBA格式，ID: {}，永久URL: {}，临时URL: {}", 
                    imageModel.getUuid(), materialUrl, materialTempUrl);
            
            return imageModel;
            
        } catch (Exception e) {
            log.error("上传引导图像异常", e);
            throw new RuntimeException("上传引导图像失败: " + e.getMessage(), e);
        }
    }

    /**
     * 图像处理（支持主体图像和引导图像）
     * 
     * 根据阿里云图像参数要求进行图像处理：
     * - base_image_url: 主体图像URL（必选，PNG格式，RGBA四通道，长边不超过2048像素）
     * - ref_image_url: 引导图像URL（可选，PNG格式，RGBA四通道，长边不超过2048像素）
     * 
     * @param baseImageModel 主体图像模型记录
     * @param refImageModel 引导图像模型记录（可选）
     * @param prompt 处理提示词
     * @param functionName 功能名称
     * @return 处理后的图像模型记录
     */
    @Override
    public ImageModel processImageWithRef(ImageModel baseImageModel, ImageModel refImageModel, 
                                          String prompt, String functionName) {
        try {
            log.info("开始图像处理，主体图像ID: {}，引导图像ID: {}，提示词: {}，功能: {}", 
                    baseImageModel.getUuid(), 
                    refImageModel != null ? refImageModel.getUuid() : "无", 
                    prompt, functionName);
            
            // 1. 验证主体图像
            if (baseImageModel.getMaterialTempUrl() == null || baseImageModel.getMaterialTempUrl().trim().isEmpty()) {
                throw new IllegalArgumentException("主体图像URL不能为空");
            }
            
            String baseImageUrl = baseImageModel.getMaterialTempUrl().trim();
            if (!isPublicAccessibleUrl(baseImageUrl)) {
                throw new IllegalArgumentException("主体图像URL必须是公网可访问的地址");
            }
            
            // 2. 验证引导图像（如果提供）
            String refImageUrl = null;
            if (refImageModel != null && refImageModel.getMaterialTempUrl() != null && 
                !refImageModel.getMaterialTempUrl().trim().isEmpty()) {
                refImageUrl = refImageModel.getMaterialTempUrl().trim();
                if (!isPublicAccessibleUrl(refImageUrl)) {
                    throw new IllegalArgumentException("引导图像URL必须是公网可访问的地址");
                }
            }
            
            // 3. 设置处理参数
            baseImageModel.setPrompt(prompt);
            baseImageModel.setModelName("wanx2.1-imageedit");
            baseImageModel.setFunctionName(functionName);
            
            // 4. 调用阿里云AI模型
            log.info("调用阿里云AI模型进行图像处理，主体图像URL: {}，引导图像URL: {}", 
                    baseImageUrl, refImageUrl);
            
            String apiKey = System.getenv("DASHSCOPE_API_KEY");
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("prompt_extend", true);

            ImageSynthesisParam param = ImageSynthesisParam.builder()
                    .apiKey(apiKey)
                    .model(baseImageModel.getModelName())
                    .function(baseImageModel.getFunctionName())
                    .prompt(baseImageModel.getPrompt())
                    .baseImageUrl(baseImageUrl)
                    .n(1)
                    .size("1024*1024")
                    .parameters(parameters)
                    .build();

            ImageSynthesis imageSynthesis = new ImageSynthesis();
            ImageSynthesisResult result = null;
            try {
                log.info("开始同步调用阿里云AI模型，参数: {}", param);
                result = imageSynthesis.call(param);
                log.info("AI模型调用完成，结果: {}", JsonUtils.toJson(result));

                // 处理结果
                if (result != null && result.getOutput() != null && !result.getOutput().getResults().isEmpty()) {
                    String resultImageUrl = result.getOutput().getResults().get(0).get("url");
                    if (resultImageUrl != null && !resultImageUrl.trim().isEmpty()) {
                        log.info("开始下载AI处理结果图片: {}", resultImageUrl);
                        
                        try {
                            // 下载图片到字节数组
                            byte[] imageBytes = downloadImageToBytes(resultImageUrl);
                            log.info("图片下载成功，大小: {} bytes", imageBytes.length);
                            
                            // 生成唯一文件名
                            String resultFileName = generateUniqueFileName("jpg");
                            
                            // 上传到MinIO
                            String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/jpeg");
                            log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
                            
                            // 生成7天临时访问链接
                            String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
                            log.info("生成7天临时访问链接: {}", resultImageTempUrl);
                            
                            // 更新ImageModel对象
                            baseImageModel.setResultImageUrl(resultImageMinIOUrl);
                            baseImageModel.setResultImageTempUrl(resultImageTempUrl);
                            
                        } catch (Exception e) {
                            log.error("下载或上传AI处理结果图片失败", e);
                            throw new RuntimeException("处理结果图片失败: " + e.getMessage(), e);
                        }
                    } else {
                        log.warn("AI处理结果中没有有效的图片URL");
                    }
                } else {
                    log.warn("AI处理结果为空或无效");
                }
                
            } catch (ApiException | NoApiKeyException e) {
                log.error("阿里云API调用失败", e);
                throw new RuntimeException("AI模型调用失败: " + e.getMessage(), e);
            }
            
            // 5. 保存处理记录
            boolean saveResult = this.updateById(baseImageModel);
            if (!saveResult) {
                log.error("保存图像处理记录失败");
                throw new RuntimeException("保存图像处理记录失败");
            }
            
            log.info("图像处理完成，ID: {}，结果URL: {}", 
                    baseImageModel.getUuid(), baseImageModel.getResultImageTempUrl());
            
            return baseImageModel;
            
        } catch (Exception e) {
            log.error("图像处理异常", e);
            throw new RuntimeException("图像处理失败: " + e.getMessage(), e);
        }
    }

    /**
     * 基础文件验证
     * 
     * 验证文件的基本要求，不限制格式（用于引导图像自动转换）
     * 
     * @param file 上传的文件
     * @throws IllegalArgumentException 文件不符合要求时抛出异常
     */
    private void validateBasicImageFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }
        
        // 检查文件大小（限制为10MB）
        long maxSize = 10 * 1024 * 1024; // 10MB
        if (file.getSize() > maxSize) {
            throw new IllegalArgumentException("文件大小不能超过10MB");
        }
        
        // 检查文件格式
        String contentType = file.getContentType();
        if (contentType == null || !contentType.startsWith("image/")) {
            throw new IllegalArgumentException("只能上传图片文件");
        }
        
        // 检查文件扩展名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        // 支持常见图像格式
        String extension = getFileExtension(originalFilename).toLowerCase();
        String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
        boolean isValidExtension = false;
        for (String allowedExt : allowedExtensions) {
            if (extension.equals(allowedExt)) {
                isValidExtension = true;
                break;
            }
        }
        
        if (!isValidExtension) {
            throw new IllegalArgumentException("不支持的图片格式，支持的格式：jpg, jpeg, png, gif, bmp, webp");
        }
    }

    /**
     * 验证图片文件
     * 
     * 根据阿里云图像参数要求进行验证：
     * - 主体图像必须为PNG格式，带透明背景的RGBA四通道图像
     * - 引导图像必须为PNG格式，带透明背景的RGBA四通道图像
     * - 图像长边不超过2048像素
     * 
     * @param file 上传的文件
     * @param imageType 图像类型（base_image主体图像 或 ref_image引导图像）
     * @throws IllegalArgumentException 文件不符合要求时抛出异常
     */
    private void validateImageFile(MultipartFile file, String imageType) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }
        
        // 检查文件大小（限制为10MB）
        long maxSize = 10 * 1024 * 1024; // 10MB
        if (file.getSize() > maxSize) {
            throw new IllegalArgumentException("文件大小不能超过10MB");
        }
        
        // 检查文件格式
        String contentType = file.getContentType();
        if (contentType == null || !contentType.startsWith("image/")) {
            throw new IllegalArgumentException("只能上传图片文件");
        }
        
        // 检查文件扩展名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        String extension = getFileExtension(originalFilename).toLowerCase();
        
        // 根据图像类型进行不同的验证
        if ("base_image".equals(imageType)) {
            // 主体图像必须是PNG格式
            if (!"png".equals(extension)) {
                throw new IllegalArgumentException("主体图像必须是PNG格式，且为带透明背景的RGBA四通道图像");
            }
            
            // 验证图像尺寸（长边不超过2048像素）
            validateImageDimensions(file);
            
        } else if ("ref_image".equals(imageType)) {
            // 引导图像必须是PNG格式，带透明背景的RGBA四通道图像
            if (!"png".equals(extension)) {
                throw new IllegalArgumentException("引导图像必须是PNG格式，且为带透明背景的RGBA四通道图像");
            }
            
            // 验证图像尺寸（长边不超过2048像素）
            validateImageDimensions(file);
        } else {
            // 默认验证（兼容原有逻辑）
            String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
            boolean isValidExtension = false;
            for (String allowedExt : allowedExtensions) {
                if (extension.equals(allowedExt)) {
                    isValidExtension = true;
                    break;
                }
            }
            
            if (!isValidExtension) {
                throw new IllegalArgumentException("不支持的图片格式，支持的格式：jpg, jpeg, png, gif, bmp, webp");
            }
        }
    }
    
    /**
     * 验证图像尺寸
     * 
     * 检查图像长边是否超过2048像素
     * 
     * @param file 上传的文件
     * @throws IllegalArgumentException 图像尺寸不符合要求时抛出异常
     */
    private void validateImageDimensions(MultipartFile file) {
        try {
            // 使用BufferedImage读取图像尺寸
            java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file.getInputStream());
            if (image == null) {
                throw new IllegalArgumentException("无法读取图像文件");
            }
            
            int width = image.getWidth();
            int height = image.getHeight();
            int maxDimension = Math.max(width, height);
            
            if (maxDimension > 2048) {
                throw new IllegalArgumentException("图像长边不能超过2048像素，当前尺寸：" + width + "x" + height);
            }
            
            log.info("图像尺寸验证通过：{}x{}", width, height);
            
        } catch (Exception e) {
            log.error("验证图像尺寸失败", e);
            throw new IllegalArgumentException("验证图像尺寸失败：" + e.getMessage());
        }
    }
    
    /**
     * 获取文件扩展名
     * 
     * @param filename 文件名
     * @return 文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null || filename.lastIndexOf('.') == -1) {
            return "";
        }
        return filename.substring(filename.lastIndexOf('.') + 1);
    }
    
    /**
     * 生成唯一文件名
     * 
     * 格式：时间戳_UUID.扩展名
     * 
     * @param extension 文件扩展名
     * @return 唯一文件名
     */
    private String generateUniqueFileName(String extension) {
        long timestamp = System.currentTimeMillis();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return timestamp + "_" + uuid + "." + extension;
    }
    
    /**
     * 验证URL是否为公网可访问的地址
     * 
     * 检查URL是否符合阿里云图像参数要求：
     * - 必须是HTTP或HTTPS协议
     * - 必须是公网可访问的地址
     * 
     * @param url 要验证的URL
     * @return 是否为公网可访问的URL
     */
    private boolean isPublicAccessibleUrl(String url) {
        if (url == null || url.trim().isEmpty()) {
            return false;
        }
        
        try {
            // 检查协议
            if (!url.startsWith("http://") && !url.startsWith("https://")) {
                log.warn("URL协议不支持，必须是HTTP或HTTPS: {}", url);
                return false;
            }
            
            // 检查是否为内网地址（简单检查）
            if (url.contains("localhost") || url.contains("127.0.0.1") || 
                url.contains("192.168.") || url.contains("10.") || url.contains("172.")) {
                log.warn("URL为内网地址，不是公网可访问: {}", url);
                return false;
            }
            
            // 尝试访问URL验证可访问性
            URL urlObj = new URL(url);
            try (InputStream inputStream = urlObj.openStream()) {
                // 如果能打开流，说明URL可访问
                log.info("URL验证通过，可公网访问: {}", url);
                return true;
            }
            
        } catch (Exception e) {
            log.warn("URL验证失败，无法公网访问: {}，错误: {}", url, e.getMessage());
            return false;
        }
    }
    
    /**
     * 将图像转换为RGBA格式
     * 
     * 将任意格式的图像转换为带透明背景的RGBA四通道PNG格式
     * 
     * @param file 原始图像文件
     * @return RGBA格式的图像字节数组
     * @throws IOException 转换失败时抛出异常
     */
    private byte[] convertToRGBA(MultipartFile file) throws IOException {
        try {
            log.info("开始转换图像为RGBA格式，原始文件: {}", file.getOriginalFilename());
            
            // 读取原始图像
            java.awt.image.BufferedImage originalImage = javax.imageio.ImageIO.read(file.getInputStream());
            if (originalImage == null) {
                throw new IllegalArgumentException("无法读取图像文件");
            }
            
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            
            // 验证图像尺寸
            int maxDimension = Math.max(width, height);
            if (maxDimension > 2048) {
                throw new IllegalArgumentException("图像长边不能超过2048像素，当前尺寸：" + width + "x" + height);
            }
            
            log.info("原始图像尺寸: {}x{}", width, height);
            
            // 创建RGBA格式的图像
            java.awt.image.BufferedImage rgbaImage = new java.awt.image.BufferedImage(
                width, height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
            
            // 获取图形上下文
            java.awt.Graphics2D g2d = rgbaImage.createGraphics();
            
            // 设置渲染提示以获得更好的质量
            g2d.setRenderingHint(java.awt.RenderingHints.KEY_INTERPOLATION, 
                                java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(java.awt.RenderingHints.KEY_RENDERING, 
                                java.awt.RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, 
                                java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
            
            // 绘制原始图像到RGBA图像上
            g2d.drawImage(originalImage, 0, 0, null);
            g2d.dispose();
            
            // 将RGBA图像转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            javax.imageio.ImageIO.write(rgbaImage, "PNG", baos);
            byte[] rgbaBytes = baos.toByteArray();
            
            log.info("图像转换完成，RGBA格式大小: {} bytes", rgbaBytes.length);
            
            return rgbaBytes;
            
        } catch (Exception e) {
            log.error("转换图像为RGBA格式失败", e);
            throw new IOException("转换图像为RGBA格式失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 下载图片到字节数组
     * 
     * 从指定URL下载图片并返回字节数组，支持超时配置
     * 
     * @param imageUrl 图片URL
     * @return 图片字节数组
     * @throws IOException 下载失败时抛出异常
     */
    private byte[] downloadImageToBytes(String imageUrl) throws IOException {
        try {
            log.info("开始下载图片: {}", imageUrl);
            
            URL url = new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            
            // 设置请求头
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(aliyunConfig.getApi().getConnectTimeout()); // 使用配置的连接超时
            connection.setReadTimeout(aliyunConfig.getApi().getReadTimeout());  // 使用配置的读取超时
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            connection.setRequestProperty("Accept", "image/*");
            connection.setRequestProperty("Accept-Encoding", "identity"); // 禁用压缩
            
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                try (InputStream inputStream = connection.getInputStream();
                     ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                    
                    byte[] buffer = new byte[8192]; // 增大缓冲区
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                    
                    byte[] imageBytes = outputStream.toByteArray();
                    log.info("图片下载完成，大小: {} bytes", imageBytes.length);
                    return imageBytes;
                }
            } else {
                log.error("下载图片失败，HTTP状态码: {}, URL: {}", responseCode, imageUrl);
                throw new IOException("HTTP error code: " + responseCode);
            }
            
        } catch (Exception e) {
            log.error("下载图片失败: {}", imageUrl, e);
            throw new IOException("下载图片失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 文本生成图像
     * 
     * 根据文本提示词生成图像，包括：
     * - 调用AI图像生成服务
     * - 处理生成结果
     * - 保存生成记录
     * 
     * @param request 文本生成图像请求参数
     * @return 生成结果，包含图像URL等信息
     */
    @Override
    public Map<String, Object> generateImageByText(TextModelController.ImageProcessingRequest request) {
        try {
            log.info("开始文本生成图像，提示词: {}，模型: {}", request.getPrompt(), request.getModel());
            
            Map<String, Object> result = new HashMap<>();
            
            // 1. 参数验证
            if (request.getPrompt() == null || request.getPrompt().trim().isEmpty()) {
                throw new IllegalArgumentException("提示词不能为空");
            }
            
            if (request.getModel() == null || request.getModel().trim().isEmpty()) {
                throw new IllegalArgumentException("模型名称不能为空");
            }
            
            // 2. 调用阿里云图像生成API
            String apiKey = System.getenv("DASHSCOPE_API_KEY");
            if (apiKey == null || apiKey.trim().isEmpty()) {
                throw new RuntimeException("未配置DASHSCOPE_API_KEY环境变量");
            }
            
            // 3. 设置API基础URL（参考测试类）
            Constants.baseHttpApiUrl = "https://dashscope.aliyuncs.com/api/v1";
            
            // 4. 构建多模态对话参数（参考测试类）
            MultiModalConversation conv = new MultiModalConversation();
            MultiModalMessage userMessage = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(
                            Collections.singletonMap("text", request.getPrompt())
                    )).build();
            
            // 5. 构建参数（参考测试类）
            Map<String, Object> parameters = new HashMap<>();
            parameters.put("watermark", true);
            parameters.put("prompt_extend", true);
            parameters.put("negative_prompt", "");
            parameters.put("size", "1328*1328");  // 使用阿里云允许的尺寸
            
            MultiModalConversationParam param = MultiModalConversationParam.builder()
                    .apiKey(apiKey)
                    .model("qwen-image-plus")  // 使用固定的模型名称
                    .messages(Collections.singletonList(userMessage))
                    .parameters(parameters)
                    .build();
            
            // 6. 调用图像生成服务
            MultiModalConversationResult conversationResult = null;
            
            try {
                log.info("开始调用阿里云多模态对话API，参数: {}", param);
                conversationResult = conv.call(param);
                log.info("多模态对话API调用完成，结果: {}", JsonUtils.toJson(conversationResult));
                
            } catch (ApiException | NoApiKeyException | UploadFileException e) {
                log.error("阿里云多模态对话API调用失败", e);
                throw new RuntimeException("图像生成API调用失败: " + e.getMessage(), e);
            }
            
            // 7. 处理生成结果
            if (conversationResult != null && conversationResult.getOutput() != null && 
                conversationResult.getOutput().getChoices() != null && 
                !conversationResult.getOutput().getChoices().isEmpty()) {
                
                log.info("图像生成成功，开始处理结果");
                log.info("完整API返回结果: {}", JsonUtils.toJson(conversationResult));
                
                // 从多模态对话结果中提取图像URL
                String generatedImageUrl = null;
                try {
                    // 根据您提供的返回结果格式解析图像URL
                    // 返回格式：{"output": {"choices": [{"message": {"content": [{"image": "url"}]}}]}}
                    var choices = conversationResult.getOutput().getChoices();
                    if (!choices.isEmpty()) {
                        var message = choices.get(0).getMessage();
                        var content = message.getContent();
                        
                        log.info("API返回的content: {}", JsonUtils.toJson(content));
                        
                        // 解析content数组中的image字段
                        if (content != null && !content.isEmpty()) {
                            // content是一个List，包含多个内容项
                            for (Object contentItem : content) {
                                if (contentItem instanceof Map) {
                                    @SuppressWarnings("unchecked")
                                    Map<String, Object> contentMap = (Map<String, Object>) contentItem;
                                    if (contentMap.containsKey("image")) {
                                        generatedImageUrl = (String) contentMap.get("image");
                                        log.info("提取到图像URL: {}", generatedImageUrl);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    
                    if (generatedImageUrl == null || generatedImageUrl.trim().isEmpty()) {
                        log.warn("未能从API返回结果中提取图像URL，完整结果: {}", JsonUtils.toJson(conversationResult));
                        throw new RuntimeException("未能从API返回结果中提取图像URL");
                    }
                    
                } catch (Exception e) {
                    log.error("解析API返回结果失败", e);
                    throw new RuntimeException("解析API返回结果失败: " + e.getMessage(), e);
                }
                
                if (generatedImageUrl != null && !generatedImageUrl.trim().isEmpty()) {
                    try {
                        log.info("开始下载生成的图片: {}", generatedImageUrl);
                        
                        // 下载图片到字节数组
                        byte[] imageBytes = downloadImageToBytes(generatedImageUrl);
                        log.info("图片下载成功，大小: {} bytes", imageBytes.length);
                        
                        // 生成唯一文件名
                        String resultFileName = generateUniqueFileName("png");
                        
                        // 上传到MinIO
                        String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/png");
                        log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
                        
                        // 生成7天临时访问链接
                        String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
                        log.info("生成7天临时访问链接: {}", resultImageTempUrl);
                        
                        // 保存图像模型记录到数据库
                        ImageModel imageModel = new ImageModel();
                        imageModel.setImageName(request.getImageName() != null ? request.getImageName() : "文本生成图像");
                        imageModel.setOwnerName(request.getOwnerName());
                        imageModel.setOwnerPhone(request.getOwnerPhone());
                        imageModel.setImageType("text_to_image");
                        imageModel.setPrompt(request.getPrompt());
                        imageModel.setModelName(request.getModel());
                        imageModel.setResultImageUrl(resultImageMinIOUrl);
                        imageModel.setResultImageTempUrl(resultImageTempUrl);
                        imageModel.setCreateTime(LocalDateTime.now());
                        imageModel.setUpdateTime(LocalDateTime.now());
                        
                        // 保存到数据库
                        boolean saveResult = this.saveImageModel(imageModel);
                        if (!saveResult) {
                            log.error("保存文本生成图像记录失败");
                            throw new RuntimeException("保存文本生成图像记录失败");
                        }
                        
                        // 构建返回结果
                        result.put("success", true);
                        result.put("message", "文本生成图像处理完成");
                        result.put("imageCount", 1);
                        result.put("imageUrl", resultImageTempUrl);
                        result.put("imageMinIOUrl", resultImageMinIOUrl);
                        result.put("prompt", request.getPrompt());
                        result.put("model", request.getModel());
                        result.put("requestId", imageModel.getUuid());
                        result.put("timestamp", LocalDateTime.now());
                        
                        log.info("文本生成图像处理完成，图像已保存到数据库，ID: {}", imageModel.getUuid());
                        
                    } catch (Exception e) {
                        log.error("处理生成的图片失败", e);
                        throw new RuntimeException("处理生成的图片失败: " + e.getMessage(), e);
                    }
                } else {
                    log.warn("生成的图片URL为空");
                    throw new RuntimeException("生成的图片URL为空");
                }
            } else {
                log.warn("图像生成结果为空");
                throw new RuntimeException("图像生成结果为空");
            }
            
            return result;
            
        } catch (Exception e) {
            log.error("文本生成图像异常", e);
            throw new RuntimeException("文本生成图像失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 图生图
     * 
     * 根据图片和指令生成新图片，包括：
     * - 验证API Key和参数
     * - 构建请求体
     * - 调用阿里云图生图API
     * - 处理异步响应
     * - 返回任务信息
     * 
     * @param multipartFile 上传的图片文件

     * @param ownerName 所属人姓名
     * @param ownerPhone 所属人电话
     * @param imageName 图片名称
     * @param model 模型名称，默认为wanx-v1
     * @param parameters 参数字符串（JSON格式）
     * @return 生成结果，包含任务ID等信息
     */
    @Override
    public Map<String, Object> generateImageToImage(MultipartFile multipartFile, String prompt,
                                                   String ownerName, String ownerPhone, String imageName, 
                                                   String model, String parameters) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            log.info("开始图生图处理，ownerName: {}, imageName: {}, refPrompt: {}", 
                    ownerName, imageName, prompt);
            
            // 1. 验证API Key
            String apiKey = System.getenv("DASHSCOPE_API_KEY");
            if (apiKey == null || apiKey.isEmpty()) {
                throw new RuntimeException("DASHSCOPE_API_KEY 环境变量未设置");
            }
            
            // 2. 上传文件到MinIO并生成临时访问URL
            log.info("开始上传文件到MinIO，文件名: {}", multipartFile.getOriginalFilename());
            log.info("文件大小: {} bytes", multipartFile.getSize());
            log.info("文件类型: {}", multipartFile.getContentType());
            
            // 生成唯一文件名
            String originalFilename = multipartFile.getOriginalFilename();
            String fileExtension = getFileExtension(originalFilename);
            String uniqueFileName = generateUniqueFileName(fileExtension);
            
            log.info("生成的文件名: {}", uniqueFileName);
            log.info("文件扩展名: {}", fileExtension);
            
            // 上传到MinIO
            long uploadStartTime = System.currentTimeMillis();
            String materialUrl = minIOService.uploadFileWithName(multipartFile, uniqueFileName);
            long uploadEndTime = System.currentTimeMillis();
            log.info("MinIO上传耗时: {} ms", uploadEndTime - uploadStartTime);
            
            String materialTempUrl = minIOService.generateTempUrl(uniqueFileName);
            
            log.info("文件上传到MinIO成功:");
            log.info("永久URL: {}", materialUrl);
            log.info("临时访问URL: {}", materialTempUrl);
            
            // 验证临时URL是否可访问
            log.info("开始验证临时URL可访问性...");
            try {
                URL testUrl = new URL(materialTempUrl);
                HttpURLConnection testConnection = (HttpURLConnection) testUrl.openConnection();
                testConnection.setRequestMethod("HEAD");
                testConnection.setConnectTimeout(10000);
                testConnection.setReadTimeout(10000);
                int testResponseCode = testConnection.getResponseCode();
                log.info("临时URL访问测试结果: HTTP {}", testResponseCode);
                if (testResponseCode != 200) {
                    log.warn("临时URL可能无法访问，这可能导致阿里云API超时");
                }
            } catch (Exception e) {
                log.error("临时URL访问测试失败: {}", e.getMessage());
            }
            
            // 输出到控制台
            System.out.println("=== 图生图文件上传信息 ===");
            System.out.println("原始文件名: " + originalFilename);
            System.out.println("生成的文件名: " + uniqueFileName);
            System.out.println("MinIO永久URL: " + materialUrl);
            System.out.println("MinIO临时访问URL: " + materialTempUrl);
            System.out.println("=========================");
            
            // 3. 创建ImageModel记录并保存到数据库
            ImageModel imageModel = new ImageModel();
            imageModel.setImageName(imageName != null ? imageName : originalFilename);
            imageModel.setOwnerName(ownerName);
            imageModel.setOwnerPhone(ownerPhone);
            imageModel.setImageType("material");
            imageModel.setPrompt(prompt);
            imageModel.setModelName(model);
            imageModel.setMaterialUrl(materialUrl);
            imageModel.setMaterialTempUrl(materialTempUrl);
            imageModel.setCreateTime(LocalDateTime.now());
            imageModel.setUpdateTime(LocalDateTime.now());
            
            // 保存到数据库
            boolean saveResult = this.saveImageModel(imageModel);
            if (!saveResult) {
                throw new RuntimeException("保存图生图记录失败");
            }
            
            log.info("图生图记录已保存到数据库，ID: {}", imageModel.getUuid());
            
            // 4. 设置API基础URL
            Constants.baseHttpApiUrl = "https://dashscope.aliyuncs.com/api/v1";
            
            // 5. 使用MultiModalConversation调用阿里云API
            MultiModalConversation conv = new MultiModalConversation();
            
            // 构建多模态消息 - 智能选择图片传递方式
            Object imageContent;
            
            // 首先尝试使用临时URL
            if (isUrlAccessible(materialTempUrl)) {
                log.info("使用临时URL传递图片: {}", materialTempUrl);
                imageContent = materialTempUrl;
            } 
            // 如果临时URL不可访问，尝试永久URL
            else if (isUrlAccessible(materialUrl)) {
                log.warn("临时URL不可访问，使用永久URL: {}", materialUrl);
                imageContent = materialUrl;
            }
            // 如果URL都不可访问，使用base64编码
            else {
                log.warn("所有URL都不可访问，尝试使用base64编码传递图片");
                try {
                    byte[] imageBytes = multipartFile.getBytes();
                    String base64Image = "data:image/" + getFileExtension(multipartFile.getOriginalFilename()) + ";base64," + 
                                       java.util.Base64.getEncoder().encodeToString(imageBytes);
                    imageContent = base64Image;
                    log.info("使用base64编码传递图片，大小: {} bytes", imageBytes.length);
                } catch (Exception e) {
                    log.error("转换为base64失败，回退到使用临时URL: {}", e.getMessage());
                    imageContent = materialTempUrl;
                }
            }
            
            MultiModalMessage userMessage = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(
                            Collections.singletonMap("image", imageContent),
                            Collections.singletonMap("text", prompt)
                    )).build();
            
            // 解析parameters参数
            Map<String, Object> parametersMap = new HashMap<>();
            if (parameters != null && !parameters.isEmpty()) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> parsedParams = objectMapper.readValue(parameters, Map.class);
                    parametersMap = parsedParams;
                } catch (Exception e) {
                    log.warn("解析parameters参数失败，使用默认值: {}", e.getMessage());
                }
            }
            
            // 设置默认参数
            parametersMap.put("watermark", false);
            if (!parametersMap.containsKey("negative_prompt")) {
                parametersMap.put("negative_prompt", " ");
            }
            
            // 构建API参数
            MultiModalConversationParam param = MultiModalConversationParam.builder()
                    .apiKey(apiKey)
                    .model(model) // 使用图生图模型
                    .messages(Collections.singletonList(userMessage))
                    .parameters(parametersMap)
                    .build();
            
            // 输出请求参数到控制台
            System.out.println("=== 发送给阿里云的请求参数 ===");
            System.out.println("模型: qwen-image-edit");
            System.out.println("图片URL: " + materialTempUrl);
            System.out.println("提示词: " + prompt);
            System.out.println("参数: " + JsonUtils.toJson(parametersMap));
            System.out.println("=========================");
            
            // 6. 调用阿里云API（带重试机制）
            log.info("开始调用阿里云图生图API");
            log.info("API配置 - 连接超时: {} ms, 读取超时: {} ms", 
                    aliyunConfig.getApi().getConnectTimeout(), 
                    aliyunConfig.getApi().getReadTimeout());
            log.info("重试配置 - 最大重试次数: {}, 重试延迟: {} ms", 
                    aliyunConfig.getApi().getMaxRetries(), 
                    aliyunConfig.getApi().getRetryDelay());
            
            MultiModalConversationResult conversationResult = null;
            int maxRetries = aliyunConfig.getApi().getMaxRetries();
            int retryCount = 0;
            
            while (retryCount < maxRetries) {
                try {
                    log.info("第{}次尝试调用阿里云API...", retryCount + 1);
                    long apiStartTime = System.currentTimeMillis();
                    
                    conversationResult = conv.call(param);
                    
                    long apiEndTime = System.currentTimeMillis();
                    log.info("阿里云API调用成功，耗时: {} ms", apiEndTime - apiStartTime);
                    break; // 成功则跳出循环
                    
                } catch (ApiException e) {
                    retryCount++;
                    log.error("阿里云API调用失败，第{}次尝试，错误详情:", retryCount);
                    log.error("错误代码: {}", e.getMessage());
                    log.error("请求ID: {}", extractRequestId(e.getMessage()));
                    
                    if (e.getMessage().contains("DataInspection") || e.getMessage().contains("timeout")) {
                        if (retryCount < maxRetries) {
                            long delayTime = aliyunConfig.getApi().getRetryDelay() * retryCount;
                            log.warn("检测到超时错误，{}ms后进行第{}次重试", delayTime, retryCount + 1);
                            try {
                                Thread.sleep(delayTime);
                            } catch (InterruptedException ie) {
                                Thread.currentThread().interrupt();
                                throw new RuntimeException("重试被中断", ie);
                            }
                        } else {
                            log.error("阿里云API调用失败，已达到最大重试次数: {}", maxRetries);
                            log.error("最终失败原因: {}", e.getMessage());
                            throw e;
                        }
                    } else {
                        log.error("非超时错误，直接抛出异常: {}", e.getMessage());
                        throw e;
                    }
                }
            }
            
            // 输出完整响应到控制台
            System.out.println("=== 阿里云API完整响应 ===");
            System.out.println(JsonUtils.toJson(conversationResult));
            System.out.println("======================");
            
            // 7. 处理生成结果
            if (conversationResult != null && conversationResult.getOutput() != null && 
                conversationResult.getOutput().getChoices() != null && 
                !conversationResult.getOutput().getChoices().isEmpty()) {
                
                log.info("图生图API调用成功，开始处理结果");
                
                // 从多模态对话结果中提取图像URL
                String generatedImageUrl = null;
                try {
                    var choices = conversationResult.getOutput().getChoices();
                    if (!choices.isEmpty()) {
                        var message = choices.get(0).getMessage();
                        var content = message.getContent();
                        
                        log.info("API返回的content: {}", JsonUtils.toJson(content));
                        
                        // 解析content数组中的image字段
                        if (content != null && !content.isEmpty()) {
                            for (Object contentItem : content) {
                                if (contentItem instanceof Map) {
                                    @SuppressWarnings("unchecked")
                                    Map<String, Object> contentMap = (Map<String, Object>) contentItem;
                                    if (contentMap.containsKey("image")) {
                                        generatedImageUrl = (String) contentMap.get("image");
                                        log.info("提取到生成图像URL: {}", generatedImageUrl);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    
                    if (generatedImageUrl == null || generatedImageUrl.trim().isEmpty()) {
                        log.warn("未能从API返回结果中提取图像URL");
                        throw new RuntimeException("未能从API返回结果中提取图像URL");
                    }
                    
                } catch (Exception e) {
                    log.error("解析API返回结果失败", e);
                    throw new RuntimeException("解析API返回结果失败: " + e.getMessage(), e);
                }
                
                // 8. 下载生成的图片并上传到MinIO
                if (generatedImageUrl != null && !generatedImageUrl.trim().isEmpty()) {
                    try {
                        log.info("开始下载生成的图片: {}", generatedImageUrl);
                        
                        // 下载图片到字节数组
                        byte[] imageBytes = downloadImageToBytes(generatedImageUrl);
                        log.info("图片下载成功，大小: {} bytes", imageBytes.length);
                        
                        // 生成唯一文件名
                        String resultFileName = generateUniqueFileName("png");
                        
                        // 上传到MinIO
                        String resultImageMinIOUrl = minIOService.uploadFile(imageBytes, resultFileName, "image/png");
                        log.info("图片上传到MinIO成功: {}", resultImageMinIOUrl);
                        
                        // 生成7天临时访问链接
                        String resultImageTempUrl = minIOService.generateTempUrl(resultFileName);
                        log.info("生成7天临时访问链接: {}", resultImageTempUrl);
                        
                        // 更新ImageModel对象
                        imageModel.setResultImageUrl(resultImageMinIOUrl);
                        imageModel.setResultImageTempUrl(resultImageTempUrl);
                        imageModel.setUpdateTime(LocalDateTime.now());
                        imageModel.setImageType("result");
                        // 更新数据库记录
                        boolean updateResult = this.updateById(imageModel);
                        if (!updateResult) {
                            log.error("更新图生图结果记录失败");
                        } else {
                            log.info("图生图结果已更新到数据库");
                        }
                        
                        // 构建返回结果
                        result.put("success", true);
                        result.put("message", "图生图处理完成");
                        result.put("imageCount", 1);
                        result.put("imageUrl", resultImageTempUrl);
                        result.put("imageMinIOUrl", resultImageMinIOUrl);
                        result.put("originalImageUrl", materialTempUrl);
                        result.put("prompt", model);
                        result.put("model", model);
                        result.put("requestId", imageModel.getUuid());
                        result.put("timestamp", LocalDateTime.now());
                        
                        log.info("✅ 图生图处理完成，结果已保存到数据库，ID: {}", imageModel.getUuid());
                        
                    } catch (Exception e) {
                        log.error("处理生成的图片失败", e);
                        throw new RuntimeException("处理生成的图片失败: " + e.getMessage(), e);
                    }
                } else {
                    log.warn("生成的图片URL为空");
                    throw new RuntimeException("生成的图片URL为空");
                }
            } else {
                log.warn("图生图结果为空");
                throw new RuntimeException("图生图结果为空");
            }
            
            return result;
            
        } catch (ApiException | NoApiKeyException | UploadFileException e) {
            log.error("阿里云API调用失败", e);
            throw new RuntimeException("阿里云API调用失败: " + e.getMessage(), e);
        } catch (Exception e) {
            log.error("图生图处理失败: {}", e.getMessage(), e);
            
            result.put("success", false);
            result.put("message", "图生图处理失败: " + e.getMessage());
            result.put("error", e.getClass().getSimpleName());
            result.put("timestamp", LocalDateTime.now());
            result.put("requestId", generateRequestId());
            
            throw new RuntimeException("图生图处理失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 生成请求ID
     * 
     * @return 唯一的请求ID
     */
    private String generateRequestId() {
        return "req_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
    }
    
    /**
     * 从错误消息中提取请求ID
     * 
     * @param errorMessage 错误消息
     * @return 请求ID，如果未找到则返回"未知"
     */
    private String extractRequestId(String errorMessage) {
        try {
            if (errorMessage != null && errorMessage.contains("requestId")) {
                int startIndex = errorMessage.indexOf("\"requestId\":\"") + 13;
                int endIndex = errorMessage.indexOf("\"", startIndex);
                if (startIndex > 12 && endIndex > startIndex) {
                    return errorMessage.substring(startIndex, endIndex);
                }
            }
        } catch (Exception e) {
            log.warn("提取请求ID失败: {}", e.getMessage());
        }
        return "未知";
    }
    
    /**
     * 检查URL是否可访问
     * 
     * @param urlString URL字符串
     * @return 如果URL可访问返回true，否则返回false
     */
    private boolean isUrlAccessible(String urlString) {
        try {
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD");
            connection.setConnectTimeout(5000); // 5秒连接超时
            connection.setReadTimeout(5000);     // 5秒读取超时
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            
            int responseCode = connection.getResponseCode();
            log.info("URL访问测试: {} -> HTTP {}", urlString, responseCode);
            return responseCode == 200;
        } catch (Exception e) {
            log.warn("URL访问测试失败: {} -> {}", urlString, e.getMessage());
            return false;
        }
    }
    
}
