package com.dora.service;

import com.dora.config.CosConfig;
import com.dora.util.OssUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.ObjectMetadata;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 结果文件转存服务
 * 将第三方AI服务提供的临时URL文件转存到自己的COS
 * 
 * @author 1818AI
 * @since 2025-10-24
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ResultFileTransferService {

    private final COSClient cosClient;
    private final CosConfig cosConfig;

    /**
     * 将远程URL的文件转存到COS
     * 
     * @param sourceUrl 源文件URL
     * @param userId 用户ID
     * @param taskNo 任务编号
     * @return COS永久URL，如果失败返回原URL
     */
    public String transferToCos(String sourceUrl, Long userId, String taskNo) {
        if (sourceUrl == null || sourceUrl.trim().isEmpty()) {
            log.warn("源URL为空，跳过转存");
            return sourceUrl;
        }

        try {
            log.info("开始转存文件到COS - 任务: {}, 源URL: {}", taskNo, sourceUrl);

            // 1. 从URL下载文件
            InputStream inputStream = downloadFile(sourceUrl);
            if (inputStream == null) {
                log.error("下载文件失败，返回原URL - 任务: {}", taskNo);
                return sourceUrl;
            }

            // 2. 生成对象键
            String fileExtension = extractFileExtension(sourceUrl);
            String uniqueFileName = generateResultFileName(userId, taskNo, fileExtension);
            String objectKey = cosConfig.getUserImgFolder() + "/" + uniqueFileName;

            // 3. 设置对象元数据
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(getContentTypeFromExtension(fileExtension));

            // 4. 上传到 COS
            cosClient.putObject(cosConfig.getBucketName(), objectKey, inputStream, metadata);
            
            // 5. 生成永久URL
            String permanentUrl = generatePermanentUrl(objectKey);
            
            log.info("文件转存成功 - 任务: {}, COS URL: {}", taskNo, permanentUrl);
            return permanentUrl;

        } catch (Exception e) {
            log.error("转存文件到COS失败 - 任务: {}, 错误: {}", taskNo, e.getMessage(), e);
            return sourceUrl; // 失败时返回原URL，确保业务不中断
        }
    }

    /**
     * 下载远程文件
     * 使用HttpURLConnection而不是RestTemplate，避免自动解码带签名的URL
     */
    private InputStream downloadFile(String url) {
        // 最多重试3次
        int maxRetries = 3;
        int retryDelay = 2000; // 2秒
        
        for (int attempt = 1; attempt <= maxRetries; attempt++) {
            HttpURLConnection connection = null;
            try {
                // 优先使用IPv4，避免IPv6网络不可达问题
                System.setProperty("java.net.preferIPv4Stack", "true");
                
                log.info("开始下载文件（尝试 {}/{}）: {}", attempt, maxRetries, url);
                
                // 对于带签名的Azure存储URL，必须保持原始URL编码格式
                // 使用HttpURLConnection可以完全控制HTTP请求，不会自动解码URL
                URL urlObj = new URL(url);
                connection = (HttpURLConnection) urlObj.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(30000); // 30秒连接超时
                connection.setReadTimeout(300000);   // 5分钟读取超时
                connection.setInstanceFollowRedirects(true);
                
                // 添加User-Agent，某些服务器可能需要
                connection.setRequestProperty("User-Agent", "Mozilla/5.0");
                
                int responseCode = connection.getResponseCode();
                if (responseCode >= 200 && responseCode < 300) {
                    InputStream inputStream = connection.getInputStream();
                    // 读取所有数据到字节数组
                    byte[] data = inputStream.readAllBytes();
                    inputStream.close();
                    log.info("文件下载成功，大小: {} bytes", data.length);
                    return new java.io.ByteArrayInputStream(data);
                } else {
                    log.error("下载文件失败，HTTP状态: {}, URL: {}", responseCode, url);
                    if (attempt < maxRetries) {
                        log.info("等待 {}ms 后重试...", retryDelay);
                        Thread.sleep(retryDelay);
                    }
                }
                
            } catch (java.net.SocketException e) {
                log.error("网络连接异常（尝试 {}/{}）: {} - URL: {}", 
                         attempt, maxRetries, e.getMessage(), url);
                if (e.getMessage().contains("Network is unreachable")) {
                    log.error("【网络不可达】可能原因：1) 服务器防火墙阻止出站连接 2) IPv6配置问题 3) DNS解析失败 4) 目标服务器不可用");
                }
                if (attempt < maxRetries) {
                    try {
                        log.info("等待 {}ms 后重试...", retryDelay);
                        Thread.sleep(retryDelay);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            } catch (Exception e) {
                log.error("下载文件异常（尝试 {}/{}）: {} - URL: {}", 
                         attempt, maxRetries, e.getClass().getSimpleName(), url, e);
                if (attempt < maxRetries) {
                    try {
                        log.info("等待 {}ms 后重试...", retryDelay);
                        Thread.sleep(retryDelay);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }
        
        log.error("下载文件失败，已重试 {} 次，放弃下载 - URL: {}", maxRetries, url);
        return null;
    }

    /**
     * 从URL提取文件扩展名
     */
    private String extractFileExtension(String url) {
        try {
            URL urlObj = new URL(url);
            String path = urlObj.getPath();
            
            if (path != null && path.contains(".")) {
                String ext = path.substring(path.lastIndexOf("."));
                // 移除查询参数
                if (ext.contains("?")) {
                    ext = ext.substring(0, ext.indexOf("?"));
                }
                return ext;
            }
            
            // 默认为mp4（大多数视频结果）
            return ".mp4";
            
        } catch (Exception e) {
            log.warn("提取文件扩展名失败，使用默认值: {}", e.getMessage());
            return ".mp4";
        }
    }

    /**
     * 生成结果文件名
     */
    private String generateResultFileName(Long userId, String taskNo, String extension) {
        String timestamp = String.valueOf(System.currentTimeMillis());
        return userId + "_" + taskNo + "_" + timestamp + extension;
    }

    /**
     * 根据扩展名获取Content-Type
     */
    private String getContentTypeFromExtension(String extension) {
        if (extension == null) {
            return "application/octet-stream";
        }
        
        switch (extension.toLowerCase()) {
            case ".mp4":
                return "video/mp4";
            case ".mov":
                return "video/quicktime";
            case ".avi":
                return "video/x-msvideo";
            case ".webm":
                return "video/webm";
            case ".jpg":
            case ".jpeg":
                return "image/jpeg";
            case ".png":
                return "image/png";
            case ".gif":
                return "image/gif";
            case ".webp":
                return "image/webp";
            default:
                return OssUtil.getContentType("file" + extension);
        }
    }

    /**
     * 生成 COS 永久URL
     */
    private String generatePermanentUrl(String objectKey) {
        // 优先使用自定义域名
        String domain = cosConfig.getCustomDomain();
        if (domain != null && !domain.isEmpty()) {
            if (!domain.startsWith("http://") && !domain.startsWith("https://")) {
                domain = "https://" + domain;
            }
            return domain + "/" + objectKey;
        }
        // 默认 COS 访问域名
        return "https://" + cosConfig.getBucketName() + ".cos." + cosConfig.getRegion() + ".myqcloud.com/" + objectKey;
    }
}
