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

import com.yd.common.result.Result;
import com.yd.oss.feign.dto.ApiMaterialDto;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
import com.yd.oss.service.service.CompressedFileService;
import com.yd.oss.service.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 压缩包服务
 */
@Slf4j
@Service
public class CompressedFileServiceImpl implements CompressedFileService {

    @Autowired
    private OssService ossService;

    @Autowired
    private String defaultBucket; // 注入默认存储桶

    @Autowired
    private String defaultEndpoint; // 注入默认服务端点


    /**
     * 下载-材料列表压缩包
     * @param request
     * @return
     */
    @Override
    public Result<ApiMaterialDownloadResponse> downloadCompressedFile(ApiMaterialDownloadRequest request) {
        try {
            // 验证请求参数
            if (request == null || CollectionUtils.isEmpty(request.getApiMaterialDtoList())) {
                return Result.fail("材料列表不能为空");
            }

            if (!StringUtils.hasText(request.getObjectName())) {
                return Result.fail("对象名（包名）不能为空");
            }

            // 创建临时压缩文件
            File tempZipFile = createTempZipFile();
            int successFileCount = 0; // 成功添加的文件计数

            try (FileOutputStream fos = new FileOutputStream(tempZipFile);
                 ZipOutputStream zos = new ZipOutputStream(fos, StandardCharsets.UTF_8)) {

                // 处理每个材料
                for (ApiMaterialDto materialDto : request.getApiMaterialDtoList()) {
                    String folderName = buildFolderName(materialDto);

                    // 处理每个文件的URL
                    if (!CollectionUtils.isEmpty(materialDto.getFileUrlList())) {
                        for (int i = 0; i < materialDto.getFileUrlList().size(); i++) {
                            String fileUrl = materialDto.getFileUrlList().get(i);
                            try {
                                // 下载文件并添加到压缩包
                                boolean success = addFileToZip(zos, fileUrl, folderName, i + 1);
                                if (success) {
                                    successFileCount++;
                                }
                            } catch (Exception e) {
                                log.warn("文件下载失败，URL: {}", fileUrl, e);
                                // 继续处理其他文件
                            }
                        }
                    }
                }

                // 刷新并关闭流
                zos.flush();
                zos.finish();

                // 如果没有成功添加任何文件，返回错误
                if (successFileCount == 0) {
                    return Result.fail("没有有效的文件可下载");
                }

                log.info("成功添加 {} 个文件到压缩包，压缩包大小: {} 字节",
                        successFileCount, tempZipFile.length());

                // 上传压缩包到OSS
                String ossUrl = uploadZipToOss(tempZipFile, request.getObjectName());

                // 构建响应
                ApiMaterialDownloadResponse response = new ApiMaterialDownloadResponse();
                response.setUrl(ossUrl);

                return Result.success(response);

            } catch (Exception e) {
                log.error("创建压缩包失败", e);
                return Result.fail("创建压缩包失败: " + e.getMessage());
            } finally {
                // 清理临时文件
                if (tempZipFile.exists()) {
                    try {
                        tempZipFile.delete();
                    } catch (Exception e) {
                        log.warn("清理临时文件失败", e);
                    }
                }
            }

        } catch (Exception e) {
            log.error("下载材料压缩包失败", e);
            return Result.fail("下载材料压缩包失败: " + e.getMessage());
        }
    }

    /**
     * 创建临时压缩文件
     */
    private File createTempZipFile() throws IOException {
        String tempDir = System.getProperty("java.io.tmpdir");
        String fileName = "material_zip_" + System.currentTimeMillis() + "_" + UUID.randomUUID() + ".zip";
        File tempFile = new File(tempDir, fileName);
        log.debug("创建临时压缩文件: {}", tempFile.getAbsolutePath());
        return tempFile;
    }

    /**
     * 构建文件夹名称：资料人-资料类型
     */
    private String buildFolderName(ApiMaterialDto materialDto) {
        String dataPerson = StringUtils.hasText(materialDto.getDataPerson()) ?
                materialDto.getDataPerson() : "未知资料人";
        String dataType = StringUtils.hasText(materialDto.getDataType()) ?
                materialDto.getDataType() : "未知类型";

        // 清理非法文件名字符
        String folderName = dataPerson + "-" + dataType;
        folderName = folderName.replaceAll("[\\\\/:*?\"<>|]", "_");
        return folderName;
    }

    /**
     * 下载文件并添加到压缩包
     */
    private boolean addFileToZip(ZipOutputStream zos, String fileUrl, String folderName, int fileIndex) throws Exception {
        // 从URL中提取文件名
        String fileName = extractFileNameFromUrl(fileUrl, fileIndex);

        // 构建zip中的完整路径
        String zipEntryName = folderName + "/" + fileName;

        // 从OSS下载文件
        InputStream fileInputStream = downloadFileFromUrl(fileUrl);
        if (fileInputStream == null) {
            throw new IOException("无法下载文件: " + fileUrl);
        }

        try {
            // 创建zip entry
            ZipEntry zipEntry = new ZipEntry(zipEntryName);
            zos.putNextEntry(zipEntry);

            // 将文件内容写入zip
            byte[] buffer = new byte[8192];
            int length;
            int totalBytes = 0;
            while ((length = fileInputStream.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
                totalBytes += length;
            }

            zos.closeEntry();
            log.debug("成功添加文件到压缩包: {} ({} 字节)", zipEntryName, totalBytes);
            return true;

        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                log.warn("关闭文件流失败", e);
            }
        }
    }

    /**
     * 从URL中提取文件名
     */
    private String extractFileNameFromUrl(String fileUrl, int fileIndex) {
        if (!StringUtils.hasText(fileUrl)) {
            return "file_" + fileIndex;
        }

        try {
            // 尝试从URL中提取文件名
            int lastSlashIndex = fileUrl.lastIndexOf('/');
            if (lastSlashIndex >= 0 && lastSlashIndex < fileUrl.length() - 1) {
                String fileName = fileUrl.substring(lastSlashIndex + 1);

                // 清理文件名
                int queryIndex = fileName.indexOf('?');
                if (queryIndex > 0) {
                    fileName = fileName.substring(0, queryIndex);
                }

                if (StringUtils.hasText(fileName) && fileName.length() < 255) {
                    return fileName;
                }
            }
        } catch (Exception e) {
            log.warn("从URL提取文件名失败: {}", fileUrl, e);
        }

        // 默认文件名
        return "file_" + fileIndex + getFileExtensionFromUrl(fileUrl);
    }

    /**
     * 从URL获取文件扩展名
     */
    private String getFileExtensionFromUrl(String fileUrl) {
        if (!StringUtils.hasText(fileUrl)) {
            return "";
        }

        try {
            // 获取扩展名
            int dotIndex = fileUrl.lastIndexOf('.');
            if (dotIndex > 0 && dotIndex < fileUrl.length() - 1) {
                String ext = fileUrl.substring(dotIndex);
                int queryIndex = ext.indexOf('?');
                if (queryIndex > 0) {
                    ext = ext.substring(0, queryIndex);
                }

                // 只保留常见的文件扩展名
                if (ext.length() <= 5 && ext.matches("\\.[a-zA-Z0-9]{1,4}")) {
                    return ext;
                }
            }
        } catch (Exception e) {
            log.warn("获取文件扩展名失败", e);
        }

        return "";
    }

    /**
     * 从URL下载文件
     */
    private InputStream downloadFileFromUrl(String fileUrl) {
        try {
            // 方法1: 尝试从OSS下载（如果URL是我们OSS的）
            String fileKey = extractFileKeyFromUrl(fileUrl);
            if (StringUtils.hasText(fileKey)) {
                log.debug("从OSS下载文件，fileKey: {}", fileKey);
                return ossService.downloadFile(fileKey);
            }

            // 方法2: 尝试HTTP下载
            log.debug("尝试HTTP下载文件: {}", fileUrl);
            return downloadFileByHttp(fileUrl);

        } catch (Exception e) {
            log.error("下载文件失败: {}", fileUrl, e);
            return null;
        }
    }

    /**
     * 从完整URL中提取OSS文件key
     */
    private String extractFileKeyFromUrl(String fileUrl) {
        if (!StringUtils.hasText(fileUrl)) {
            return null;
        }

        try {
            // 你提供的URL格式: https://yd-ali-oss.oss-cn-shanghai-finance-1-pub.aliyuncs.com/docx/2026/01/06/166b192397f84055aaec968d20e57977.docx

            // 移除协议前缀
            String url = fileUrl;
            if (url.startsWith("https://")) {
                url = url.substring(8);
            } else if (url.startsWith("http://")) {
                url = url.substring(7);
            }

            // 从配置获取endpoint
            String endpoint = defaultEndpoint;

            // 查找bucket.endpoint组合
            String bucketEndpoint = defaultBucket + "." + endpoint;
            int bucketEndpointIndex = url.indexOf(bucketEndpoint);

            if (bucketEndpointIndex >= 0) {
                // 提取bucket.endpoint之后的部分
                int startIndex = bucketEndpointIndex + bucketEndpoint.length();
                if (url.charAt(startIndex) == '/') {
                    startIndex++;
                }

                String fileKey = url.substring(startIndex);

                // 移除查询参数
                int queryIndex = fileKey.indexOf('?');
                if (queryIndex > 0) {
                    fileKey = fileKey.substring(0, queryIndex);
                }

                log.debug("从URL提取fileKey: {} -> {}", fileUrl, fileKey);
                return fileKey;
            }

            // 尝试其他可能的格式
            int firstSlashIndex = url.indexOf('/');
            if (firstSlashIndex > 0) {
                String fileKey = url.substring(firstSlashIndex + 1);

                // 移除查询参数
                int queryIndex = fileKey.indexOf('?');
                if (queryIndex > 0) {
                    fileKey = fileKey.substring(0, queryIndex);
                }

                log.debug("从URL提取fileKey（备选）: {} -> {}", fileUrl, fileKey);
                return fileKey;
            }

        } catch (Exception e) {
            log.warn("从URL提取文件key失败: {}", fileUrl, e);
        }

        return null;
    }

    /**
     * HTTP下载文件
     */
    private InputStream downloadFileByHttp(String fileUrl) {
        try {
            URL url = new URL(fileUrl);
            URLConnection connection = url.openConnection();
            connection.setConnectTimeout(10000); // 10秒连接超时
            connection.setReadTimeout(30000);    // 30秒读取超时

            // 设置User-Agent，避免被某些服务器拒绝
            connection.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");

            return connection.getInputStream();
        } catch (Exception e) {
            log.error("HTTP下载文件失败: {}", fileUrl, e);
            return null;
        }
    }

    /**
     * 上传压缩包到OSS
     */
    private String uploadZipToOss(File zipFile, String objectName) throws Exception {
        if (!zipFile.exists() || zipFile.length() == 0) {
            throw new IOException("压缩文件不存在或为空");
        }

        try (FileInputStream fis = new FileInputStream(zipFile)) {
            // 生成压缩包文件名
            String zipFileName = generateZipFileName(objectName);

            log.info("上传压缩包到OSS，文件大小: {} 字节，文件名: {}",
                    zipFile.length(), zipFileName);

            // 检查是否使用阿里云OSS实现
            if (ossService instanceof AliYunOssServiceImpl) {
                AliYunOssServiceImpl aliYunOssService = (AliYunOssServiceImpl) ossService;

                // 使用反射调用upload方法（兼容性更好）
                try {
                    // 方法1: 直接调用public方法
                    java.lang.reflect.Method uploadMethod = AliYunOssServiceImpl.class
                            .getMethod("upload", InputStream.class, String.class);

                    String ossUrl = (String) uploadMethod.invoke(aliYunOssService, fis, zipFileName);
                    log.info("压缩包上传成功，URL: {}", ossUrl);
                    return ossUrl;

                } catch (NoSuchMethodException e) {
                    // 方法2: 尝试其他可能的upload方法
                    log.warn("未找到upload(InputStream, String)方法，尝试其他方法");

                    // 转换为字节数组上传
                    byte[] zipBytes = readFileToBytes(zipFile);
                    try {
                        java.lang.reflect.Method uploadMethod2 = AliYunOssServiceImpl.class
                                .getMethod("upload", byte[].class, String.class);

                        String ossUrl = (String) uploadMethod2.invoke(aliYunOssService, zipBytes, zipFileName);
                        log.info("压缩包上传成功，URL: {}", ossUrl);
                        return ossUrl;
                    } catch (NoSuchMethodException e2) {
                        // 最后尝试：使用现有的uploadFile方法
                        log.info("尝试使用现有的uploadFile方法");
                        return uploadUsingExistingMethod(fis, zipFileName, "system");
                    }
                }
            } else {
                throw new UnsupportedOperationException("不支持的OSS服务类型");
            }
        }
    }

    /**
     * 使用现有的uploadFile方法上传
     */
    private String uploadUsingExistingMethod(InputStream inputStream, String fileName, String uploadUser) throws Exception {
        // 这里需要根据你的OssService接口的具体方法进行调整
        // 假设有uploadFile(InputStream, String, String)方法
        try {
            // 读取整个文件到字节数组
            byte[] fileData = readInputStreamToBytes(inputStream);

            // 使用反射调用upload(byte[], String)方法
            java.lang.reflect.Method uploadMethod = AliYunOssServiceImpl.class
                    .getMethod("upload", byte[].class, String.class);

            AliYunOssServiceImpl aliYunOssService = (AliYunOssServiceImpl) ossService;
            return (String) uploadMethod.invoke(aliYunOssService, fileData, fileName);

        } catch (Exception e) {
            log.error("使用现有方法上传失败", e);
            throw e;
        }
    }

    /**
     * 读取文件到字节数组
     */
    private byte[] readFileToBytes(File file) throws IOException {
        try (FileInputStream fis = new FileInputStream(file);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[8192];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                bos.write(buffer, 0, length);
            }
            return bos.toByteArray();
        }
    }

    /**
     * 读取输入流到字节数组
     */
    private byte[] readInputStreamToBytes(InputStream inputStream) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[8192];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                bos.write(buffer, 0, length);
            }
            return bos.toByteArray();
        }
    }

    /**
     * 生成压缩包文件名
     */
    private String generateZipFileName(String objectName) {
        // 清理非法字符
        String safeObjectName = objectName.replaceAll("[\\\\/:*?\"<>|]", "_");

        // 添加时间戳和扩展名
        String fileName = safeObjectName + "_" +
                new java.text.SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) +
                ".zip";

        log.debug("生成的压缩包文件名: {}", fileName);
        return fileName;
    }
}